Подтвердить что ты не робот

Как использовать Rack:: Proxy в Rails для прокси-запросов для определенного пути к другому приложению

Я нашел это замечательное сообщение о том, как использовать Rack::Proxy в качестве отдельного прокси-приложения. В статье объясняется, как он использует Rack::Proxy для прокси-запросов к http://localhost:3000 для приложения на порту 3001 и обращается к http://localhost:3000/api к приложению на порту 3002. Я хочу сделать то же самое, но я не хочу создавать отдельное прокси-приложение. Вместо этого я хочу, чтобы мое основное приложение Rails запрашивало прокси-запросы /blog в другое приложение.

Сообщение в блоге: http://livsey.org/blog/2012/02/23/using-rack-proxy-to-serve-multiple-rails-apps-from-the-same-domain-and-port/

4b9b3361

Ответ 1

Выяснил это.

Библиотека /proxy.rb
require 'rack-proxy'
class Proxy < Rack::Proxy
    def initialize(app)
        @app = app
    end

    def rewrite_env(env)
        # do magic in here
    end
 end
конфиг /application.rb
config.middleware.use "Proxy"

Ответ 2

FWIW, я также просто решил эту проблему. Некоторые могут найти полный код полезным, так как мне нужно больше, чем вы разместили:

# lib/proxy_to_other.rb
class ProxyToOther < Rack::Proxy
  def initialize(app)
    @app = app
  end

  def call(env)
    original_host = env["HTTP_HOST"]
    rewrite_env(env)
    if env["HTTP_HOST"] != original_host
      perform_request(env)
    else
      # just regular
      @app.call(env)
    end
  end

  def rewrite_env(env)
    request = Rack::Request.new(env)
    if request.path =~ %r{^/prefix|^/other_prefix}
      # do nothing
    else
      env["HTTP_HOST"] = "localhost:3000"
    end
    env
  end
end

также:

# config/application.rb
# ...snip ...
module MyApplication
  class Application < Rails::Application
    # Custom Rack middlewares
    config.middleware.use "ProxyToOther" if ["development", "test"].include? Rails.env
#...snip....

Это предполагает, что ваше приложение, к которому вы хотите проксировать некоторые запросы, работает на порт 3001. Я полагаю, приложение, которое вы нажимаете, может быть запущено на любом порту. Это также предполагает, что вы хотите только проксировать в средах разработки и тестирования, потому что у вас будет "реальное" решение в производстве и постановке (например, nginx или loadbalancer, которые делают правильную вещь).

Ответ 3

Это небольшое изменение для решения steve, которое использует немного меньшее внутреннее понимание Rack::Proxy:

require 'rack/proxy'

class MyProxy < Rack::Proxy
  def initialize(app)
    @app = app
  end

  def call(env)
    # call super if we want to proxy, otherwise just handle regularly via call
    (proxy?(env) && super) || @app.call(env)
  end

  def proxy?(env)
    # do not alter env here, but return true if you want to proxy for this request.
    return true
  end

  def rewrite_env(env)
    # change the env here
    env["HTTP_HOST"] = "some.other.host"
    env
  end
end

Ответ 4

Ниже приведен еще более простой код для прокси-сервера api, если вы хотите http://localhost:3000/api/users/1 (например), чтобы перейти в пространство имен api, определенное в routes.rb без использования прокси-серверной программы.

В процессе создания было бы что-то вроде http://api.sample.com/users/1.

Библиотека /proxy.rb

require 'rack-proxy'

class Proxy < Rack::Proxy
   def perform_request(env)
     request = Rack::Request.new(env)
     if request.path =~ %r{^/api}
       #do nothing
     else
       @app.call(env)
     end
   end
end

конфигурации /application.rb

config.middleware.use "Proxy"

конфигурации /routes.rb

namespace :api, defaults: { format: :json },
        constraints: { subdomain: 'api' }, path: '/'  do
  scope module: :v1, constraints: ApiConstraints.new(version: 1, default: true) do
  resources :users, :only => [:show, :create, :update, :destroy]
end

Библиотека /api _constraints.rb

class ApiConstraints
  def initialize(options)
    @version = options[:version]
    @default = options[:default]
  end

  def matches?(req)
    @default || req.headers['Accept'].include?("application/vnd.sample.v#{@version}")
  end
end