【问题标题】:How To Pass Multiple Parameters In A URL To Plug如何在要插入的 URL 中传递多个参数
【发布时间】:2014-10-11 18:17:24
【问题描述】:

所以我试图在一个 URL 中传递多个参数来插入。这是我用于测试的 URL:

http://localhost:4000/uid=ToddFlanders&pwd=MyTestPword

这是代码:

defmodule Sci do
    @userid "uid"
    @password "pwd"
    import Plug.Conn
    import Plug.Conn.Utils
    use Plug.Router


    plug :match
    plug :dispatch

    get "/:args" do
        %{@userid => usr} = params(args)
        %{@password => pass} = params(args)

        send_resp(conn, 200, "Hello #{usr}. Your password is #{pass}")
    end

    match _ do
        send_resp(conn, 404, "oops")
  end

  def start do
    Plug.Adapters.Cowboy.http Sci, [], port: 4000
  end

  def stop do
    Plug.Adapters.Cowboy.shutdown Sci.HTTP
  end
end

如果我只传递一个参数(uid 或 pwd),它匹配得很好。如果我删除查询字符串前面的?,它会失败——抛出异常。

我也试过这个:

get "/:args" do
  %{@userid => usr, @password => pass} = params(args)

也没有用。所以两个问题:

1.) 这是在 URL 中传递多个参数的正确方法吗?

2.) 是否有一些技巧可以让插件同时查看两个参数?

欢迎任何想法或见解 - 甚至建议更好的方法来做到这一点。

Elixir v0.15.1 和 Plug v0.5.1

编辑:

根据 Jose 的评论添加堆栈跟踪:

iex(2)> 07:46:56.499 [error] Error in process <0.232.0> with exit value: {[{reason,{badmatch,#{}}},{mfa,{'Elixir.Plug.Adapters.Cowboy.Handler',init,3}},{stacktrace,[{'Elixir.Sci','-do_match/2-fun-0-',2,[{file,"lib/sci.ex"},{line,18}]},{'Eli
xir.Sci',call,2,[{file,"lib/sci.ex"},{line,1}]},{'Elixir.Plug.Adapters.Cowboy.Handler'...                                                                                                                                                       


iex(2)> 07:46:56.510 [error] Ranch listener Sci.HTTP had connection process started with :cowboy_protocol:start_link/4 at #PID<0.232.0> exit with reason: {[reason: {:badmatch, %{}}, mfa: {Plug.Adapters.Cowboy.Handler, :init, 3}, stacktrace:
 [{Sci, :"-do_match/2-fun-0-", 2, [file: 'lib/sci.ex', line: 18]}, {Sci, :call, 2, [file: 'lib/sci.ex', line: 1]}, {Plug.Adapters.Cowboy.Handler, :init, 3, [file: 'lib/plug/adapters/cowboy/handler.ex', line: 7]}, {:cowboy_handler, :handler_
init, 4, [file: 'src/cowboy_handler.erl', line: 64]}, {:cowboy_protocol, :execute, 4, [file: 'src/cowboy_protocol.erl', line: 435]}], req: [socket: #Port<0.5168>, transport: :ranch_tcp, connection: :keepalive, pid: #PID<0.232.0>, method: "G
ET", version: :"HTTP/1.1", peer: {{127, 0, 0, 1}, 63880}, host: "localhost", host_info: :undefined, port: 4000, path: "/uid=ToddFlanders&pwd=MyTestPassword", path_info: :undefined, qs: "", qs_vals: :undefined, bindings: [], headers: [{"host
", "localhost:4000"}, {"connection", "keep-alive"}, {"cache-control", "max-age=0"}, {"accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8"}, {"user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/53
7.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36"}, {"accept-encoding", "gzip,deflate,sdch"}, {"accept-language", "en-US,en;q=0.8"}], p_headers: [{"connection", ["keep-alive"]}], cookies: :undefined, meta: [], body_state: :waitin
g, buffer: "", multipart: :undefined, resp_compress: false, resp_state: :waiting, resp_headers: [], resp_body: "", onresponse: :undefined], opts: {Sci, []}], [{:cowboy_protocol, :execute, 4, [file: 'src/cowboy_protocol.erl', line: 435]}]}  

iex(2)> 07:46:56.969 [error] Error in process <0.233.0> with exit value: {[{reason,{badmatch,#{}}},{mfa,{'Elixir.Plug.Adapters.Cowboy.Handler',init,3}},{stacktrace,[{'Elixir.Sci','-do_match/2-fun-0-',2,[{file,"lib/sci.ex"},{line,18}]},{'Eli
xir.Sci',call,2,[{file,"lib/sci.ex"},{line,1}]},{'Elixir.Plug.Adapters.Cowboy.Handler'...                                                                                                                                                       


iex(2)> 07:46:56.971 [error] Ranch listener Sci.HTTP had connection process started with :cowboy_protocol:start_link/4 at #PID<0.233.0> exit with reason: {[reason: {:badmatch, %{}}, mfa: {Plug.Adapters.Cowboy.Handler, :init, 3}, stacktrace:
 [{Sci, :"-do_match/2-fun-0-", 2, [file: 'lib/sci.ex', line: 18]}, {Sci, :call, 2, [file: 'lib/sci.ex', line: 1]}, {Plug.Adapters.Cowboy.Handler, :init, 3, [file: 'lib/plug/adapters/cowboy/handler.ex', line: 7]}, {:cowboy_handler, :handler_
init, 4, [file: 'src/cowboy_handler.erl', line: 64]}, {:cowboy_protocol, :execute, 4, [file: 'src/cowboy_protocol.erl', line: 435]}], req: [socket: #Port<0.5174>, transport: :ranch_tcp, connection: :keepalive, pid: #PID<0.233.0>, method: "G
ET", version: :"HTTP/1.1", peer: {{127, 0, 0, 1}, 63881}, host: "localhost", host_info: :undefined, port: 4000, path: "/favicon.ico", path_info: :undefined, qs: "", qs_vals: :undefined, bindings: [], headers: [{"host", "localhost:4000"}, {"
connection", "keep-alive"}, {"accept", "*/*"}, {"user-agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36"}, {"accept-encoding", "gzip,deflate,sdch"}, {"accept-language", "e
n-US,en;q=0.8"}], p_headers: [{"connection", ["keep-alive"]}], cookies: :undefined, meta: [], body_state: :waiting, buffer: "", multipart: :undefined, resp_compress: false, resp_state: :waiting, resp_headers: [], resp_body: "", onresponse: 
:undefined], opts: {Sci, []}], [{:cowboy_protocol, :execute, 4, [file: 'src/cowboy_protocol.erl', line: 435]}]}                                                                                                                                 

编辑 2: 我在上面记下了错误的 URL;现在已经纠正了。还要补充一点,如果我将 URL 设为:http://localhost:4000/?uid=ToddFlanders&amp;pwd=MyTestPword,则代码会跳转到match _ do 子句

【问题讨论】:

  • 你遇到了什么失败?你能发布堆栈跟踪吗?而且你肯定需要在之前调用 fetch_params。
  • 我已经添加了堆栈跟踪。我之前犹豫要不要添加它,因为我不太清楚如何格式化它。
  • 啊,我明白了。 :args 不会包含查询字符串。它将只包含路径。如果要访问查询字符串参数,则需要完全按照 sasa 建议的方式进行操作。这基本上是调用fetch_params(conn) 并以conn.params 访问它。

标签: elixir


【解决方案1】:

我不擅长使用 Plug,但对于演示代码,我使用了 fetch_params/1,然后使用了 conn.params["foo"]conn.params["bar"] 等等,这确实有效。

更新:由于 Plug 0.12.0,应该使用fetch_query_params/2

【讨论】:

  • 这是一个很好的建议,但它似乎仍然不起作用。你能给我指点你的演示代码吗?
  • 我没有在线,但这里有一个草图:gist.github.com/sasa1977/99cc0526f5b4dd903e21
  • 此答案中的文档链接现在导致 404,我收到了 (UndefinedFunctionError) undefined function Plug.Conn.fetch_params/1。这个功能是否被其他东西取代了? (附:我很喜欢你的书!)
  • fetch_query_params 看起来像实际的函数名称。
  • @CoderDennis 是的,这发生在 0.12.0,请参阅 github.com/elixir-lang/plug/blob/…。我会更新答案,感谢您指出这一点。 (附言很高兴你喜欢这本书 :-))
【解决方案2】:

您要使用的 URL 结构的格式并不正确。 因此,您的问题与框架无关,因为几乎所有框架/库在以您预期的方式解析 URL 时都会遇到问题。

/uid=ToddFlanders&amp;pwd=MyTestPword 被视为没有任何查询参数的路径。

PATH: /uid=ToddFlanders&pwd=MyTestPword
QUERY STRING: (empty/unset)
QUERY PARAMS: [ ]

我猜你真的很想拥有像/?uid=ToddFlanders&amp;pwd=MyTestPword 这样的东西。

PATH: /
QUERY STRING: uid=ToddFlanders&pwd=MyTestPword
QUERY PARAMS: [ uid: "ToddFlanders", pwd: "MyTestPword" ]

此外,Plug.Conn.Utils.params/1 旨在解析标头参数。使用Plug.Conn.Query.decode/1 代替查询参数。

因此,在您的示例中,我建议将应用程序代码调整如下:

defmodule Sci do
  import Plug.Conn
  use Plug.Router

  @userid   "uid"
  @password "pwd"

  plug :match
  plug :dispatch

  get "/" do
    conn = fetch_params(conn) # populates conn.params
    %{ @userid => usr, @password => pass } = conn.params
    send_resp(conn, 200, "Hello #{usr}. Your password is #{pass}")
  end

  match _ do
    send_resp(conn, 404, "oops")
  end

  def start do
    Plug.Adapters.Cowboy.http Sci, [], port: 4000
  end

  def stop do
    Plug.Adapters.Cowboy.shutdown Sci.HTTP
  end
end

然后你可以成功尝试http://localhost:4000/?uid=ToddFlanders&amp;pwd=MyTestPword

(此外,它不应该命中 match(_) 函数,因为如果您正确地对该路径执行请求,/ 应该始终匹配。

【讨论】:

  • 好的,我不得不承认标题参数和查询参数之间的区别对我来说并不清楚,但在阅读了您的回复(以及其他回复之后),我发现我混淆了这两个想法。
【解决方案3】:

您现在应该使用fetch_query_paramshttps://hexdocs.pm/plug/Plug.Conn.html#fetch_query_params/2

【讨论】:

    猜你喜欢
    • 2013-11-21
    • 2012-06-12
    • 2016-02-20
    • 1970-01-01
    • 2018-08-06
    • 1970-01-01
    • 1970-01-01
    • 2020-09-06
    • 1970-01-01
    相关资源
    最近更新 更多