25 Stimmen

Wie verwende ich Rack::Proxy in Rails, um Anfragen an einen bestimmten Pfad an eine andere App weiterzuleiten?

Ich habe diesen großartigen Blog-Beitrag darüber gefunden, wie man Rack::Proxy als separate Proxy-App verwendet. Der Artikel erklärt, wie er Rack::Proxy benutzt, um Anfragen an http://localhost:3000 an eine App auf Port 3001 und Anfragen an http://localhost:3000/api an eine App auf Port 3002 weiterzuleiten. Ich möchte dasselbe tun, möchte aber keine separate Proxy-App erstellen. Stattdessen möchte ich, dass meine Haupt-Rails-App Anfragen an /blog an eine andere App weiterleitet.

Blog-Beitrag: http://livsey.org/blog/2012/02/23/using-rack-proxy-to-serve-multiple-rails-apps-from-the-same-domain-and-port/

32voto

steve Punkte 3054

Zum Thema: FWIW, habe ich dieses Problem gerade auch angegangen. Manche finden den vollständigen Code hilfreich, da ich mehr als das, was du gepostet hast, benötigt habe:

# 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
      # nur normal
      @app.call(env)
    end
  end

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

Außerdem:

# config/application.rb
# ...Ausschnitt...
module MyApplication
  class Application < Rails::Application
    # Eigene Rack-Middlewares
    config.middleware.use "ProxyToOther" if ["development", "test"].include? Rails.env
#...Ausschnitt...

Dies setzt voraus, dass deine App, zu der du einige Anfragen weiterleiten möchtest, auf Port 3001 läuft. Ich würde sagen, die App, die du angreifst, kann auf jedem Port ausgeführt werden. Das setzt auch voraus, dass du das Weiterleiten nur in Entwicklungs- und Testumgebungen machen möchtest, da du in Produktions- und Staging-Umgebungen eine "echte" Lösung haben wirst (z.B. nginx oder ein Lastenausgleicher, der die richtigen Dinge macht).

17voto

wbyoung Punkte 22083

Dies ist eine geringfügige Änderung an Steves Lösung, die etwas weniger internes Verständnis von Rack::Proxy verwendet:

require 'rack/proxy'

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

  def call(env)
    # rufe super auf, wenn wir einen Proxy verwenden möchten, ansonsten behandeln wir ihn einfach über call
    (proxy?(env) && super) || @app.call(env)
  end

  def proxy?(env)
    # Bearbeite den env hier nicht, aber gib true zurück, wenn du für diese Anfrage einen Proxy verwenden möchtest.
    return true
  end

  def rewrite_env(env)
    # Ändere den env hier
    env["HTTP_HOST"] = "some.other.host"
    env
  end
end

3voto

John Punkte 8924

Figured it out.

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

config/application.rb

config.middleware.use "Proxy"

Verstanden.

lib/proxy.rb

require 'rack-proxy'
class Proxy < Rack::Proxy
    def initialize(app)
        @app = app
    end

    def rewrite_env(env)
        # Hier Magie durchführen
    end
end

config/application.rb

config.middleware.use "Proxy"

1voto

mrlindsey Punkte 300

Im Folgenden finden Sie einen noch einfacheren Code, um eine API zu proxieren, wenn Sie möchten, dass http://localhost:3000/api/users/1 (zum Beispiel) zum im routes.rb definierten API-Namespace geht, ohne ein Proxy-Server-Programm zu verwenden.

Auf der Produktionsumgebung würde es etwas wie http://api.sample.com/users/1 sein.

lib/proxy.rb

require 'rack-proxy'

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

config/application.rb

config.middleware.use "Proxy"

config/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]

lib/api_constraints.rb

  end
end

1voto

oklas Punkte 7133

Ich fand das Juwel rails-reverse-proxy einfacher und offensichtlicher zu verwenden (für React-App):

Fügen Sie einen einfachen Proxy-Controller hinzu:

class ProxyController < ApplicationController
  include ReverseProxy::Controller

  def index
    reverse_proxy "http://localhost:3000" do |config|
      # Wir haben einen 404 Fehler bekommen!
      config.on_missing do |code, response|
        redirect_to root_url and return
      end
    end
  end
end

Und fügen Sie eine Route hinzu:

match 'static/*path' => 'proxy#index', via: [:get, :post, :put, :patch, :delete]

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X