web-dev-qa-db-ja.com

Rails内でRack :: Proxyを使用して、リクエストを別のアプリへの特定のパスにプロキシするにはどうすればよいですか?

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 /

19
John

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またはロードバランサーが適切な処理を実行します)。

29
steve

これは、Rack::Proxyの内部理解を少し少なくするsteveのソリューションへのわずかな変更です。

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
14
wbyoung

以下は、必要なときにapiをプロキシするさらに簡単なコードです http:// localhost:3000/api/users/1 (たとえば)routes.rbで定義されたapi名前空間にaを使用せずに移動しますプロキシサーバープログラム。

本番環境では、 http://api.sample.com/users/1 のようになります。

lib/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

config/application.rb

config.middleware.use "Proxy"

config/routers.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

lib/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
1
mrlindsey