Приложение Sinatra как промежуточное ПО для стоек TimesOut Rails 3

Находясь в среде разработки Rails, я пытаюсь добавить приложение Sinatra в качестве промежуточного программного обеспечения. Приложение Sinatra использует geoip-гем, который обрабатывает IP-адрес пользователя и возвращает его город в формате JSON.

Я могу просмотреть возвращенный json, перейдя непосредственно к URL-адресу примера в браузере или используя curl в командной строке, http://local.fqdn.org/geoip/locate.json?ip=24.18.211.123. Однако, когда я пытаюсь вызвать URL-адрес с помощью wget из контроллера Rails, приложение Rails перестает отвечать, часто приводя к сбою моего браузера, и мой сервер rails не выходит с помощью команды control + C.

Любая подсказка о том, что здесь происходит? Почему переход непосредственно к URL-адресу в браузере возвращает правильный ответ, но мой вызов в контроллере приводит к тайм-ауту?

sinatra-geoip.rb

require 'sinatra'
require 'geoip'
require 'json'

# http://localhost/geoip/locate.json?ip=24.18.211.123
#
# {
#     latitude: 47.684700012207
#     country_name: "United States"
#     area_code: 206
#     city: "Seattle"
#     region: "WA"
#     longitude: -122.384803771973
#     postal_code: "98117"
#     country_code3: "USA"
#     country_code: "US"
#     dma_code: 819
# }

class GeoIPServer < Sinatra::Base
    get '/geoip/locate.json' do
        c = GeoIP.new('/var/www/mywebsite.org/current/GeoLiteCity.dat').city(params[:ip])
        body c.to_h.to_json
    end
end

routes.rb

mount GeoIPServer => "/geoip"

config/environments/development.rb

Website::Application.configure do
    require "sinatra-geoip"
    config.middleware.use "GeoIPServer"

...
end

контроллер

raw_geo_ip = Net::HTTP.get(URI.parse("http://#{geoip_server}/geoip/locate.json?ip=#{request.ip}"))
@geo_ip = JSON.parse(raw_geo_ip)

person Jahkobi Digital    schedule 30.09.2013    source источник


Ответы (1)


Наше решение было трудно найти. В итоге мы нашли метод в исходном коде Sinatra, вызывающий forward.

новый sinatra-geoip.rb

class GeoIPServer < Sinatra::Base
    if defined?(::Rails)
        get '/properties.json' do
            env["geo_ip.lookup"] = geo_ip_lookup(request.ip)
            forward
        end
    end

    def geo_ip_lookup(ip = nil)
        ip = ip.nil? ? params[:ip] : ip
        result = GeoIP.new('/var/www/mywebsite.org/current/GeoLiteCity.dat').city(ip)
        result.to_h.to_json
    end
end

По сути, мы удалили маршрут /geoip/locate.json из файла и преобразовали его в простой метод. Нам нужно было, чтобы поиск geoip происходил при вызове properties.json, поэтому был добавлен новый параметр с информацией о geoip. Затем мы устанавливаем новый параметр равным @geo_ip переменной в контроллере.

Новый контроллер свойств

if Rails.env.development? or Rails.env.test?
    # Retrieves param set by sinatra-geoip middleware.
    @geo_ip = JSON.parse(env["geo_ip.lookup"] || "{}")
else
    # Production and staging code
end

Довольно неясная проблема и решение. Надеюсь, это поможет кому-то там. Ура!

person Jahkobi Digital    schedule 04.10.2013
comment
Мне это помогло. Спасибо, что поделились решением :) - person Ricardo Otero; 26.05.2014