需求背景

想使用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:

    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(burp0_url, headers=burp0_headers, data=multipart_encoder)

boundary放置分隔符,结束符好像会根据这个分隔符自动生成。
单K=V形式都很简单,一看就懂,多K=V形式的就按照他的格式配就好:"file": ("app-debug.apk", open('D:\\xxxx.apk', 'rb'), 'application/octet-stream').

参考

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

02-13 01:22