需求背景

  想使用requests做一个自动上传的功能,发现这里问题挺多的,比如直接发POST包,或者直接data=二进制流,都会上传失败。我觉得应该挺多人会遇到这个问题,就记录一下。

如上图上传功能,一般分为input标签,非input标签。我这里也不管什么标签,直接抓包看数据流。

Content-Type为传输内容的类型,一般有如下几种:

  • application/x-www-form-urlencoded:默认的编码方式。 在最早的http post请求中,只支持application/x-www-form-urlencoded,参数都是通过浏览器的url传递。其实是不支持文件上传的,这样有很多不便。

  • multipart/form-data:用于支持向服务器发送二进制数据,指定传输数据为二进制类型,比如图片、mp3、文件。

  • text/plain:纯文体的传输。空格转换为 “+” 加号,但不对特殊字符编码。

  • application/json 等

还有好多类型,建议查谷哥。了解到我们现在要上传multipart/form-data类型的数据,那么我们看看他的格式结构如何。

multipart/form-data 格式结构解析

格式如下:

POST /xxxxxxx/upload/ HTTP/1.1
Host: xxxxx.xxxxxxxxxxxx.cn
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.9 Safari/537.36
Accept: */*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------2385610611750
Content-Length: 1616477
Connection: close
Referer: http://xxxxxx.xxxxxxx.cn/ -----------------------------2385610611750
Content-Disposition: form-data; name="id" WU_FILE_0
-----------------------------2385610611750
Content-Disposition: form-data; name="name" app-debug.apk
-----------------------------2385610611750
Content-Disposition: form-data; name="type" application/octet-stream
-----------------------------2385610611750
Content-Disposition: form-data; name="lastModifiedDate" 2019/10/16 下午8:18:58
-----------------------------2385610611750
Content-Disposition: form-data; name="size" 1615720
-----------------------------2385610611750
Content-Disposition: form-data; name="file"; filename="app-debug.apk"
Content-Type: application/octet-stream PKxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(二进制数据流,很长...)
-----------------------------2385610611750--

格式大致分为如下几种模块:

  • 分隔符
  • 单 Key = Value 键值对
  • 多 Key = Value 键值对
  • 结束符

相信你看完我上面那么用心的截图,很容易就看懂它这种分片格式了,懂了格式就好构造了。

使用requests-toolbelt的MultipartEncoder 构造

python-requests是一个实用程序的集合,感觉基本就是用于辅助requests,最常用的功能就是使用MultipartEncoder构造上面说的这种multipart/form-data类型的数据。

官网:https://pypi.org/project/requests-toolbelt/

Demo:

import requests
from requests_toolbelt.multipart.encoder import MultipartEncoder def up():
url= 'xxx';
headers={x:x}; multipart_encoder = MultipartEncoder(
fields={
"id": "WU_FILE_0",
"name": "app-debug.apk",
"type": "application/octet-stream",
"lastModifiedDate": "2019/10/16",
"filename": "app-debug.apk",
"Content-Type": "application/octet-stream",
"file": (
"app-debug.apk", open('D:\\xxxx.apk', 'rb'), 'application/octet-stream')
},
boundary='-----------------------------2385610611750'
) result = requests.post(url, headers=headers, data=multipart_encoder)

boundary放置分隔符,结束符好像会根据这个分隔符自动生成。

单K=V形式都很简单,一看就懂,多K=V形式的就按照他的格式配就好:"file": ("app-debug.apk", open('D:\\xxxx.apk', 'rb'), 'application/octet-stream').

关于boundary的作用

boundary参考:https://stackoverflow.com/questions/3508338/what-is-the-boundary-in-multipart-form-data

boundary示例如下图:

这个boundary的作用就是类似URL提交参数时(www.baidu.com?id=22&name=lisi),作用和&是一模一样的,只不过这个分割的是浏览器自定义(随机生成)的,一般为字母或数字。只要这个分割符不和参数里面的值有一模一样就不有什么问题,服务器接收到整个数据包的时候,只是通过这个分隔符来分割参数,不会去校验这个boundary,只会去校验里面参数值是否符合条件。

Content-Type: multipart/form-data; boundary=--133951685715237
Content-Length: 1617044
Origin: https://www.testin.net
Connection: close
Referer: https://www.testin.net/app/search-list.htm ----133951685715237
Content-Disposition: form-data; name="id" 182832
----133951685715237
Content-Disposition: form-data; name="fileMd5" 35403faf30dc7b90354945c789d649f7
----133951685715237
Content-Disposition: form-data; name="sign" WU_FILE_0
----133951685715237--

格式如上,boundary=--133951685715237,只有两个--,参数分割的时候----133951685715237,有四个----,最后标记结束符的时候还需要多两个--,----133951685715237--。

如果是使用requests_toolbelt的话,只需要设置和Content-Type: multipart/form-data; boundary=--133951685715237boundary=xxx即可,因为它会自动帮助你调整格式。

参考文章

https://www.jianshu.com/p/0023bb7afddb

https://blog.csdn.net/xuezhangjun0121/article/details/82023320

https://blog.csdn.net/liyingke112/article/details/70233776

https://my.oschina.net/lykops/blog/1506911

https://stackoverflow.com/questions/3508338/what-is-the-boundary-in-multipart-form-data

最新文章

  1. PRML读书后记(一): 拟合学习
  2. C#中REF和OUT的区别
  3. DOM属性操作
  4. IRC(Internet Relay Chat Protocol) Protocal Learning && IRC Bot
  5. 关于php cgi的配置
  6. java中向JTextArea中添加滚动条(垂直的和水平的)
  7. 菜鸟学Linux命令:ssh命令 远程登录
  8. NoSQL 35 个非主流数据库
  9. 读取jar内的配置文件
  10. PHP 对数组数值进行排序,使用另一个容器
  11. ASP.NET MVC 5入门小结
  12. 独家分享——大牛教你如何学习Web前端开发
  13. 深入Java虚拟机读书笔记第一章Java体系结构介绍
  14. C陷阱与缺陷(三)
  15. mac随手笔记
  16. 多个onload事件写法
  17. eclipse 开发web 项目,使用gradle 需要安装的插件
  18. 01-使用eclipse新建一个标准的 java web项目
  19. 20175316盛茂淞 2018-2019-2 《Java程序设计》第9周学习总结
  20. jmeter的介绍和使用二

热门文章

  1. Go操作NSQ
  2. 013 turtle程序语法元素分析
  3. spring cloud config使用mysql存储配置文件
  4. Filter过滤器学习
  5. Spring Cloud官方文档中文版-服务发现:Eureka客户端
  6. Winform中使用ZedGraph实现曲线图中字体去掉边框
  7. mysql简易导入excel
  8. 04 (OC)* weak的实现原理
  9. SpringBoot区块链之以太坊开发(整合Web3j)
  10. spring中ehcache的配置和使用方法