【问题标题】:How to access file uploads / POST in Elixir / Plug如何在 Elixir / Plug 中访问文件上传 / POST
【发布时间】:2021-06-29 12:53:58
【问题描述】:

有很多关于如何使用 Phoenix 进行此操作的信息,但我有意避免使用 Phoenix,直到我了解有关 Elixir 工作原理的更多信息。

为此,我有以下Plug.Router 路径:

defmodule ElixirHttpServer do
  use Plug.Router
  use Plug.ErrorHandler

  plug(Plug.Parsers, parsers: [:urlencoded, {:multipart, length: 1_000_000_000}])
  plug(Plug.Logger)
  plug(:match)
  plug(:dispatch)


  post "/upload" do
    IO.inspect(Plug.Conn.read_body(conn), label: "body")
    send_resp(conn, 201, "Uploaded")
  end
end

接受来自表单的文件上传,以EEx 模板呈现:

<form action="/upload" method="post" enctype="multipart/form-data">
  <input type="file">
  <input type="submit">
</form>

通过此表单上传文件时,我从IO.inspect(Plug.Conn.read_body(conn)) 得到以下输出:

18:11:13.097 [info]  POST /upload                                                                                                                                                                                                                                                [205/3062]
body: {:ok, "",
 %Plug.Conn{
   adapter: {Plug.Cowboy.Conn, :...},
   assigns: %{},
   before_send: [#Function<1.128679493/1 in Plug.Logger.call/2>],
   body_params: %{},
   cookies: %Plug.Conn.Unfetched{aspect: :cookies},
   halted: false,
   host: "localhost",
   method: "POST",
   owner: #PID<0.750.0>,
   params: %{},
   path_info: ["upload"],
   path_params: %{},
   port: 8080,
   private: %{
     plug_multipart: :done,
     plug_route: {"/upload",
      #Function<1.2199674/2 in ElixirHttpServer.do_match/4>}
   },
   query_params: %{},
   query_string: "",
   remote_ip: {127, 0, 0, 1},
   req_cookies: %Plug.Conn.Unfetched{aspect: :cookies},
   req_headers: [
     {"accept",
      "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"},
     {"accept-encoding", "gzip, deflate, br"},
     {"accept-language", "en-US,en;q=0.9"},
     {"cache-control", "no-cache"},
     {"connection", "keep-alive"},
     {"content-length", "44"},
     {"content-type",
      "multipart/form-data; boundary=----WebKitFormBoundary4wTVqggydpkBg30n"},
     {"host", "localhost:8080"},
     {"origin", "http://localhost:8080"},
     {"pragma", "no-cache"},
     {"referer", "http://localhost:8080/"},
     {"sec-ch-ua",
      "\" Not;A Brand\";v=\"99\", \"Google Chrome\";v=\"91\", \"Chromium\";v=\"91\""},
     {"sec-ch-ua-mobile", "?0"},
     {"sec-fetch-dest", "document"},
     {"sec-fetch-mode", "navigate"},
     {"sec-fetch-site", "same-origin"},
     {"sec-fetch-user", "?1"},
     {"upgrade-insecure-requests", "1"},
     {"user-agent",
      "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36"}
   ],
   request_path: "/upload",
   resp_body: nil,
   resp_cookies: %{},
   resp_headers: [{"cache-control", "max-age=0, private, must-revalidate"}],
   scheme: :http,
   script_name: [],
   secret_key_base: nil,
   state: :unset,
   status: nil
 }}

18:11:13.099 [info]  Sent 201 in 2ms

我已经多次阅读Plug.Upload 文档,但它似乎主要是一个您可以使用的结构。

Plug.Parsers 文档说明如下,但我不知道“启动:plug 应用程序”的实际含义:

文件处理

如果文件是通过任何解析器上传的,Plug 将流式传输 将内容上传到临时目录中的文件,以避免 将整个文件加载到内存中。为此, :plug 应用程序 需要启动文件上传才能正常工作。更多详情 如何处理上传的文件可以在文档中找到 即插即用。

上传文件时,标识该文件的请求参数 文件将是一个 Plug.Upload 结构,其中包含有关上传的信息 文件(例如文件名和内容类型)以及文件的位置 存储。

我将:plug 添加到我的extra_applications,但这似乎没有任何改变:

  def application do
    [
      extra_applications: [:plug, :plug_cowboy, :logger],
      mod: {ElixirHttpServer.Application, []}
    ]
  end

  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
      {:plug_cowboy, "~> 2.4"},
      {:hackney, "~> 1.17.0"},
      {:ex_aws, "~> 2.1"},
      {:ex_aws_s3, "~> 2.0"},
      {:configparser_ex, "~> 4.0"},
      {:sweet_xml, "~> 0.6"}
    ]
  end
end

作为参考,这是我的主管申请:

defmodule ElixirHttpServer.Application do
  @moduledoc "OTP application for S3 bucket list/upload"

  use Application
  require Logger

  def start(_type, _args) do
    children = [
      {Plug.Cowboy, scheme: :http, plug: ElixirHttpServer, options: [port: cowboy_port()]}
    ]

    opts = [strategy: :one_for_one, name: ElixirHttpServer.Supervisor]

    Logger.info("Starting the application...")
    Supervisor.start_link(children, opts)
  end

  defp cowboy_port(), do: Application.get_env(:elixir_http_server, :cowboy_port, 8080)
end

【问题讨论】:

    标签: elixir plug


    【解决方案1】:

    我的input type="file" 元素缺少name 属性。

    &lt;input type="file" name="file"&gt; 成功了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-10-05
      • 2011-02-07
      • 1970-01-01
      • 1970-01-01
      • 2019-12-28
      • 2022-01-08
      • 1970-01-01
      相关资源
      最近更新 更多