1 HTTP协议上的文件上传,最频繁的应用场景了。 RFC1867里定义的标准HTTP协议POST报文格式如下:
HEADER:
Content-Type: multipart/form-data;
BODY:
Content-type: multipart/form-data, boundary=AaB03x --AaB03x content-disposition: form-data; name="field1" Joe Blow --AaB03x content-disposition: form-data; name="pics" Content-type: multipart/mixed, boundary=BbC04y --BbC04y Content-disposition: attachment; filename="file1.txt"
注释:
1 传文件的时候 使用的Media Type name: multipart , Media subtype name: form-data
2 boundary用来标识分割不同的field,其中文件是一个特殊的field
3 多个文件的时候得继续制定 Content-type: multipart/mixed ,同时定义新的 boundary
4 不同的field注意区分 Content-disposition 的值,是 form/data 还是 attachment
5 这里定义的是POST方式的上传,不针对PUT 。
2 如果需求非常确定每次请求只上传一个文件,那么我们可以不使用HTTP约定的这种方式,而改用一种更简单直接的方式:
- 在 HEDER 里的 POST 后的URL里携带普通参数 field
- 在 BODY里直接装在要上传的文件内容,抛弃任何格式等约束
- 服务端直接从BODY里读取流数据保存为文件,其他参数从URL里读取
这样以来HTTP报文就类似:
HEDER
Host: www.yangzt.com:9190
Content-Length: xxxxx
BODY
注释:
1 这不是标准的文件上传方式,但仍然是标准的HTTP报文
2 这种私有约定的方式,需要服务端和客户端同时特异化处理
3 针对每次请求只传一个文件的需求,这样改良后就会比较简洁,至于效率上是否有明显差别还不得而知,未做测试对比
3 总结:
在HTTP协议这一层上做文件的上传下载,也是很常见的方式,尤其很多移动应用里会采用;因为对客户端来说打开一个URL来GET或POST数据,相比打开一个scocke连接来读取或写入数据要简单得多,实现也快捷高效。
HTTP协议上的上传下载,也可以轻松实现断点续传,和进度反馈等,主要依赖length和range两个值。所以作为标准考虑,一定要明确地设置header里的length属性 --- 如果不设置,对于一般浏览器来说无碍,仍然可以成功下载,但是对于诸如libcurl这样的类库来说则无法取到数据。
另外,TCP协议层上的文件上传下载,也是很常见的应用场景,改日再次涉及另作详谈。