Rack::Proxy
を個別のプロキシアプリとして使用する方法について、これはすばらしいと思いました ブログ投稿 。この記事では、彼がRack::Proxy
を使用してhttp://localhost:3000
へのリクエストをポート3001
のアプリにプロキシし、http://localhost:3000/api
へのリクエストをポート3002
のアプリにプロキシする方法について説明しています。同じことをしたいのですが、別のプロキシアプリを作成したくありません。代わりに、メインのRailsアプリが、リクエストを/blog
から別のアプリにプロキシするようにします。
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またはロードバランサーが適切な処理を実行します)。
これは、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
以下は、必要なときに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