HTTP 的 POST 参数提交和上传的不同与 Mojolicious 的实现.
对于 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.1 User-Agent: Mojolicious (Perl) Connection: keep-alive Content-Type: application/x-www-form-urlencoded Accept-Encoding: gzip Content-Length: 9 Host: 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.1 User-Agent: Mojolicious (Perl) Content-Type: multipart/form-data; boundary=WRoHX Connection: keep-alive Accept-Encoding: gzip Content-Length: 14428 Host: www.php-oa.com --WRoHX Content-Disposition: form-data; name="args" test --WRoHX Content-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 中实现异步以块方式存储文件. 这样用户上传多少, 我存多少, 并不会占用更多的内存.
好了整个三种方式都介绍完了, 大家一定注意区分哦 .
建议继续学习:
- JSONP与POST方式请求 (阅读:10378)
- YSLOW法则中,为什么yahoo推荐用GET代替POST? (阅读:10020)
- 使用file_get_contents提交http post (阅读:6717)
- POST与GET的区别及RESTful (阅读:6544)
- 如何在nginx的access log中记录post请求的参数 (阅读:3304)
- Ajax还是普通Post? (阅读:2297)
- 改造 Mojolicious 让日志显示当前模块和行号 (阅读:1201)
- 使用 Mojolicious 写非阻塞的应用: Part 1 (阅读:1063)
- 使用 Mojolicious 写非阻塞的应用: Part 2 (阅读:947)
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:扶 凯 来源: 扶凯
- 标签: Mojolicious POST
- 发布时间:2014-11-19 23:26:45
- [69] Twitter/微博客的学习摘要
- [67] IOS安全–浅谈关于IOS加固的几种方法
- [65] 如何拿下简短的域名
- [65] android 开发入门
- [63] find命令的一点注意事项
- [62] Go Reflect 性能
- [61] 流程管理与用户研究
- [60] Oracle MTS模式下 进程地址与会话信
- [59] 图书馆的世界纪录
- [57] 读书笔记-壹百度:百度十年千倍的29条法则