Python requests-toolbelt庫 生成文件上傳的multipart/form-data格式數據


需求背景

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM