有很多关于如何使用Phoenix的信息,但在了解更多关于Elixir的工作原理之前,我有意避免使用Phoenic。
为此,我有以下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文档说明如下,但我不知道";启动CCD_ 4应用程序";实际意思是:
文件处理
如果文件是通过任何一个解析器上传的,Plug将流式传输将内容上载到临时目录中的文件,以避免将整个文件加载到内存中。例如:plug应用程序需要启动才能进行文件上传。有关的更多详细信息如何处理上传的文件可以在的文档中找到Plug.Upload.
上传文件时,用于标识文件将是一个Plug.Upload结构,其中包含有关已上载的文件(例如文件名和内容类型(以及文件所在的位置存储。
我在extra_applications
中添加了:plug
,但这似乎没有改变任何东西:
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
我缺少input type="file"
元素的name
属性。
<input type="file" name="file">
做到了。