1

我正在尝试编写一个中间件,它将为查询字符串设置额外的参数。用例是能够添加额外的身份验证令牌,例如,根据后端的要求添加到请求中,但希望独立于请求创建本身来注入它。

这就是我的中间件(伪代码)的样子:

class MyMiddleware < Struct.new(:app, :key, :value) 
  def call(env)
    env.params[key] = value #1
    #env.params = {key => value} #2
    app.call env
  end
end
  1. 上面引发了 NoMethodError(未定义的方法 []=' for nil:NilClass)`
  2. 上面设置了参数哈希,但参数没有编码为查询字符串的一部分。查询字符串保持中间件开始处理请求之前的状态。

我的分析是,由于查询字符串是从 rack_builder.rb:191 中的参数构建的

def build_response(connection, request)
  app.call(build_env(connection, request))
end

def build_env(connection, request)
  Env.new(request.method, request.body,
    connection.build_exclusive_url(request.path, request.params), #<== rack_builder.rb:191
    request.options, request.headers, connection.ssl,
    connection.parallel_manager)
end

中间件没有机会设置额外的参数。虽然 env 有一个 params 属性,但它是 nil 并且在中间件被调用期间或之后似乎没有被触及。

所以,我有以下问题: 1. 是否有支持的方式来实现这一目标?2. 如果没有,有没有办法重建查询字符串作为中间件执行的一部分?3. 将 URL 构建推迟到大多数请求中间件链执行之后会更好吗(当然,在适配器开始做它的事情之前;或者在适配器中做它)?4. 还有其他选择吗?

感谢任何指导。

4

1 回答 1

2

答案在 github:https ://github.com/lostisland/faraday/issues/483 by @mislav

在中间件内部,请求 URL 已经与字符串中所有配置的查询参数一起完全构建。添加或删除查询参数的唯一方法是编辑 env.url.query 字符串,例如:

MyMiddleware = Struct.new(:app, :token) do
  def call(env)
    env.url.query = add_query_param(env.url.query, "token", token)
    app.call env
  end

  def add_query_param(query, key, value)
    query = query.to_s
    query << "&" unless query.empty?
    query << "#{Faraday::Utils.escape key}=#{Faraday::Utils.escape value}"
  end
end

conn = Faraday.new "http://example.com" do |f|
  f.use MyMiddleware, "MYTOKEN"
  f.adapter :net_http
end

但是,如果您的中间件将像上面的 MyMiddleware 并且只是为所有请求添加一个静态查询参数,那么更简单的方法是避免使用中间件,只需配置 Faraday 连接实例以将相同的查询参数应用于所有请求:

conn = Faraday.new "http://example.com" do |f|
  f.params[:token] = "MYTOKEN"
  f.adapter :net_http
end
于 2016-03-31T08:18:11.407 回答