在流水线phoenix framework
中,我们可以为某些路由启用指定中间件,例如:
defmodule HelloPhoenix.Router do
use HelloPhoenix.Web, :router
pipeline :browser do
plug :accepts, ["html"]
plug :fetch_session
plug :fetch_flash
plug :protect_from_forgery
plug :put_secure_browser_headers
end
pipeline :api do
plug :accepts, ["json"]
end
scope "/", HelloPhoenix do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
end
scope "/api", HelloPhoenix do
pipe_through :api
end
end
如果来自/api
的请求,只会触发中间件plug :accepts, ["json"]
如果来自/
的请求,将触发会话,闪存,...等中间件
如果我使用grape
构建 API 和 Rails 构建网页并相互启用差异中间件,如何在 Rails 上实现这一点?
与 Phoenix 应用程序不同,您无法(轻松(更改 Rails 中用于请求的中间件。在 Rails 应用程序中获取这种行为的最佳方法是使特定路由的控制器继承自公共基本控制器,然后在该基本控制器中定义这些特定控制器的行为。
使用上面通过不同"中间件"的/api
路由示例,您可以拥有这样的控制器:
module API
class BaseController < ActionController::API
# things unique to API routes go here
end
end
在此控制器中,您可以编写一些before_action
回调来确保以下内容:
- 入站请求仅是 JSON
- 使用特定令牌对请求进行身份验证
然后,您可以从此控制器继承所有 API 控制器:
module API
class PostsController < API::BaseController
end
end
使用常规控制器,您可以执行所有常规操作:
class ApplicationController < ActionController::Base
# things unique to non-api routes go here
end
然后:
class PostsController < ApplicationController
end
您当然可以对其进行更多细分; 也许您可能有另一条路线,例如/accounts/1/posts
您必须作为该帐户的用户进行身份验证才能查看帖子。您可以采用相同的方法:
module Accounts
class BaseController < ActionController::Base
# find account, check if the user is authenticated, etc.
end
end
和:
module Accounts
class PostsController < Accounts::BaseController
end
end
总而言之:Rails 不允许你在路由级别(很容易(做到这一点,但你可以在控制器级别完成同样的事情。
我一直在寻找的解决方案是这个方向:
应用程序.rb:
# after Bundler.require(...)
require_relative '../lib/engines/website/lib/website'
lib/engines/website/lib/website.rb:
require_relative "website/engine"
module Website; end
lib/engines/website/lib/website/engine.rb:
module Website
class Engine < ::Rails::Engine
middleware.use ActionDispatch::Cookies
middleware.use ActionDispatch::Session::CookieStore
middleware.use ActionDispatch::Flash
end
end
config/routes.rb:
mount Website::Engine => "/website"
网站的所有内容都位于引擎目录下的典型目录结构中:
lib
engines
website
app
assets
...
controllers
...
views
...
config
routes.rb
lib
website
website.rb
参考:在 Rails 应用程序中构建 2 个中间件堆栈
我很确定您可以通过配置 Rack 中间件堆栈来实现此结果,但它在 rails 应用程序中不可配置。 有时,为某些路由提供不必要的中间件是可以承受的。
我看到的几乎所有应用程序都为每个请求使用相同的中间件。
是的,Phoenix 的行为在这里更好,Rails 行为在最早的版本中完成,所以现在很难改变一些东西。