HTTP 的 POST 参数提交和上传的不同与 Mojolicious 的实现.

2016-12-06 10:40:44来源:作者:IT技术博客大学习人点击

第七城市

对于 HTTP 协议, 我们在使用 POST 上传的时候, 其实是有好几种不同的处理方式的, 所以对于客户端和服务器端, 也分别都有不同的处理. 正常普通的网页在提交参数上传到服务器的时候, 主要会根据内容的不同来使用不同的处理. 所体现在不同的地方在 Content-Type 的类型.

比如我们常常用 Mojolicious 处理这类接收到的参数和内容的时候, 会让很多人晕掉, 所以我在这, 基于协议的头, 来给大家介绍一下在参数和上传的时候有什么不同.

客户端, 比如浏览器网页中的 form 的表格的参数的不同, 客户端比如 Linux 命令行的 curl 的参数的不同和程序接口提交参数的不同, HTTP 协议在上传的时候, 大约会有三种不同, 这些体现在 Content-Type 的三种类型:

application/x-www-form-urlencoded

multipart/form-data

post 的 body 的内容

下面我们来详细介绍

1. application/x-www-form-urlencoded 默认

浏览器:在 HTML 中 form 有个参数是 enctype 属性用于指定编码方式, 常用有前面讲的两种: application/x-www-form-urlencoded 和 multipart/form-data. 但默认的时候, 我们并不指定. 不指定的时候, 默认是 "application/x-www-form-urlencoded" , 所以其实, 我们平时都是使用的这种格式来提交数据. 因为是默认就不写出来了. 注意, 这个会对空格和特别的符号进行 url 的 encode.

程序:我们现在以 Mojo::UserAgent 这个模块为例子, 我们提交一个参数 args 值为 test.

$ua->post('http://www.php-oa.com/a/b'=> form => { args => 'test'});

命令:

$curl-svo /dev/null -d "args=test"http://www.php-oa.com/a/b

HTTP 协议状态

这个时候所发送的 HTTP 的头和内容分别如下. body 中会存着参数, 会有一个特别的 Header.

-- Blocking request (http://www.php-oa.com/a/b)-- Connect(http:www.php-oa.com:80)-- Client >>> Server (http://www.php-oa.com/a/b)POST /a/b HTTP/1.1User-Agent: Mojolicious (Perl)Connection: keep-aliveContent-Type: application/x-www-form-urlencodedAccept-Encoding: gzipContent-Length: 9Host: www.php-oa.com args=test

服务端接收方式

这个时候, 服务器会根据因为是 POST 的方法, 并且头部的 Content-Type: application/x-www-form-urlencoded 会去解析 body 的参数. 这样在 Mojolicious 服务器

post '/a/b'=> sub{ my$self= shift; my$foo = $self->param('args'); $self->render(text => "Hello from $foo.");} 2. multipart/form-data 大文件, 媒体文件

对于比较大的, 有一些二进制数据和象视频文件之类大文件, 建议使用这种方式上传.

浏览器:

普通的 HTTP 的写法如果要使用 enctype 的话, 只要象下面一样就行.

<form action="/path/to/login"enctype="multipart/form-data"> <input disabled="disabled"name="first_name"type="text"/> <input value="Ok"type="submit"/></form>

客户端:

在 Mojo::UserAgent 考虑得非常周全, 当你提交的内容中包含二进制文件之类时, 就会自动帮你转换成 "multipart/form-data" 格式提交. 这个格式会生成一个随机字符来分割不同参数. 区分是否使用这种格式主要是, 当你提交的参数中, 又是一个引用, 并且引中可以使用 content 来指定内容或者 file 来指定路径.

$ua->post('http://www.php-oa.com/a/b'=> form => { args => 'test', args_file => { file => '/root/.bash_history'} }); # or$ua->post('http://www.php-oa.com/a/b'=> form => { args => 'test', args_file => { content => 'test'} });

HTTP 协议状态

这个地方我们可以见到 Content-Type: multipart/form-data 的请求头, 告诉文件和参数是这种格式上传过来的.并且 boundary 用于指定一个参数之间的分割符.

-- Blocking request (http://www.php-oa.com/a/b)-- Connect(http:www.php-oa.com:80)-- Client >>> Server (http://www.php-oa.com/a/b)POST /a/b HTTP/1.1User-Agent: Mojolicious (Perl)Content-Type: multipart/form-data; boundary=WRoHXConnection: keep-aliveAccept-Encoding: gzipContent-Length: 14428Host: www.php-oa.com --WRoHXContent-Disposition: form-data; name="args"test--WRoHXContent-Disposition: form-data; name="args_file"; filename=".bash_history"........文件本身

服务器接收方式

在后端的服务器接收的时候 Mojolicious 想得非常周到. 对于这种格式能自动解析, 并且全程异步.不会多占内存. 这个会自动给大的文件使用一个叫 Mojo::Upload 的对象来处理, 我们可以通过 $self->req->upload('args_file'); 这个方法取得这个内容的对象, 这个内容的对象是Mojo::Asset::File 这个对象, 存文件和取大文件之类可以直接调用.

post '/a/b'=> sub{ my$self= shift; my$upload= $self->req->upload('args_file'); my$foo = $self->param('args'); $self->render(text => "Hello from $foo.");} 3. POST 的 body 的内容

最后一种, 是有时我们做大文件上传, 和提交内容之类.这个时候, 整个 body 都是文件本体. 参数象 get 一样通过 url 传过去.

这个就不用抓头了, 没任何转换, 直接整个 body 是个大文件.

客户端提交:

我们来看看客户端在这个时候怎么上传送. 同样, 我们使用 Mojo::UserAgent 为例子.

my$ua= Mojo::UserAgent->new;$ua->transactor->add_generator(stream => sub{ my($transactor, $tx, $path) = @_; $tx->req->content->asset(Mojo::Asset::File->new(path => $path));});$ua->post('http://www.php-oa.com/a/b'=> stream => '/root/.bash_history');

服务器接收

这个时候, 在服务器端怎么接收啦?

post '/a/b'=> sub{ my$self= shift; my$body= $self->req->body; my$foo = $self->param('args'); $self->render(text => "Hello from $foo.");}

这个, 我们直接取请求的 body 就可以了, 但这有个小问题, 这是这个文件上传完, 这个 body 会存着所有的文件, 比如这个上传的文件有 1G , 这个 1G 就都会占着内存. 这个情况, Mojolicious 并没有实现事件来根据块取文件. 晚点, 我有个有于大文件上传的文章, 会分享我在 Mojolicious 中实现异步以块方式存储文件. 这样用户上传多少, 我存多少, 并不会占用更多的内存.

好了整个三种方式都介绍完了, 大家一定注意区分哦 .

第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台