問題描述:使用微信云開發http api 上傳文件,微信返回錯誤碼400,結果格式是xml:
<?xml version='1.0' encoding='utf-8' ?>
MalformedPOSTRequest The body of your POST request is not well-formed multipart/form-data. cos.ap-shanghai.myqcloud.com/6465-develop-0388d0-1258644315/test/test_1/userlist.csv NWRjMjg1OWFfZWFiYjFjMDlfMmI3NDdfY2M1NWQ4 OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTczMmZiNDZmZjBmNTVjMGU4NTViNDhhYWVjNzNkNzI4MzIyMTZjZTI0YWNhOTM4ZDlhNGM3NDA5MDQ1NjE3NTM=
過程和解決方法下文再表。
近一年來,想要弄個微信小游戲出來,但是苦于各種原因,總是斷斷續續,到現在還沒有一個拿的出的作品。最近一段時間,看了微信云開發的相關文檔,感覺有必要寫個類庫封裝一下云Api,方便以后調用。于是就著手寫了一個簡單的調用庫,過程中基本順利。直到編寫調用云存儲,進行文件上傳時,遇到了問題。而遍尋百度和谷歌,都沒有找到相應的解決辦法,所以想著把排錯過程記錄下來,以方便其他使用.net core 進行微信云開發的同學們進行討論和參考。 筆者首先調用HTTP API的 uploadFile,成功的返回了數據,如圖: 以下為微信官方的要求: 根據要求,代碼實現如下(注意,下面這段代碼不能正確上傳,如果需要正確結果代碼的,請拉到文末):
public BaseResult uploadFile ( string path
, byte [ ] fileBuff
) { string resultContent
= "" ; try { var uploadFilePathResult
= getUploadFilePath ( path
) ; using ( HttpClient client
= new HttpClient ( ) ) { string boundary
= "-----------" + DateTime
. Now
. Ticks
. ToString ( "x" ) ; var formContent
= new MultipartFormDataContent ( boundary
) ; formContent
. Add ( new StringContent ( path
) , "\"key\"" ) ; formContent
. Add ( new StringContent ( uploadFilePathResult
. authorization
) , "\"Signature\"" ) ; formContent
. Add ( new StringContent ( uploadFilePathResult
. token
) , "\"x-cos-security-token\"" ) ; formContent
. Add ( new StringContent ( uploadFilePathResult
. cos_file_id
) , "\"x-cos-meta-fileid\"" ) ; var fileContent
= new ByteArrayContent ( fileBuff
) ; fileContent
. Headers
. ContentDisposition
= new System. Net. Http. Headers. ContentDispositionHeaderValue ( "form-data" ) { Name
= "\"file\"" , FileName
= "\"userlist.csv\"" } ; fileContent
. Headers
. ContentType
= new System. Net. Http. Headers. MediaTypeHeaderValue ( "text/csv" ) ; formContent
. Add ( fileContent
) ; formContent
. Headers
. Remove ( "Content-Type" ) ; formContent
. Headers
. Add ( "Content-Type" , "multipart/form-data; boundary=" + boundary
) ; var r
= client
. PostAsync ( uploadFilePathResult
. url
, formContent
) . Result
; var resultContentTask
= r
. Content
. ReadAsStringAsync ( ) ; resultContentTask
. Wait ( ) ; resultContent
= resultContentTask
. Result
; } } catch ( Exception e
) { } var result
= JsonConvert
. DeserializeObject < BaseResult > ( resultContent
) ; return result
; }
以上代碼,筆者使用httpclient向微信提供的url推送驗證信息和二進制文件。 但是當筆者使用測試用例,微信返回錯誤碼400,結果格式是xml:
<?xml version='1.0' encoding='utf-8' ?>
MalformedPOSTRequest The body of your POST request is not well-formed multipart/form-data. cos.ap-shanghai.myqcloud.com/6465-develop-0388d0-1258644315/test/test_1/userlist.csv NWRjMjg1OWFfZWFiYjFjMDlfMmI3NDdfY2M1NWQ4 OGVmYzZiMmQzYjA2OWNhODk0NTRkMTBiOWVmMDAxODc0OWRkZjk0ZDM1NmI1M2E2MTRlY2MzZDhmNmI5MWI1OTczMmZiNDZmZjBmNTVjMGU4NTViNDhhYWVjNzNkNzI4MzIyMTZjZTI0YWNhOTM4ZDlhNGM3NDA5MDQ1NjE3NTM=
大致的意思是我的Post請求的body不是格式正確的multipart / form-data。 于是筆者嘗試了各種方式(中間省略一兩千字。。。),花了半天的時間仍然找不到原因。 過程中,筆者用了Nodejs 的Express,建立了一個服務端,用于查看post過來的數據是否正確。服務端代碼:
var express
= require ( 'express' ) ;
var app
= express ( ) ;
var multipart
= require ( 'connect-multiparty' ) ; var multipartMiddleware
= multipart ( ) ;
app
. post ( '/post' , multipartMiddleware
, function ( req
, res
) { res
. header ( 'Access-Control-Allow-Origin' , '*' ) ; console
. log ( 'get headers: ' , req
. headers
) ; console
. log ( 'get FormData Params: ' , req
. body
) ; res
. json ( { result
: 'success' , data
: req
. body
} ) ;
} ) ;
app
. listen ( 3000 ) ;
但是一直沒有發現問題,Nodejs的服務端可以正確解釋Post請求的body和file。 于是,筆者使用Postman,將微信返回的上傳文件驗證信息和驗證信息,發送到微信服務器,發現竟然成功了!如下圖: 于是乎,連忙把Postman的請求地址改為Nodejs服務端地址,如圖: 再運行測試用例,將類庫調用地址改為本地地址: 分別向本地的nodejs服務端發送請求,并記錄日志。 對兩次請求的body和file進行對比,一直沒發現問題。直到我打印出header信息,如下圖: 注意對比,看到什么不同了嗎? 居然問題是出在content-type的boundary上!一個參數的值有用雙引號括起來,一個沒有。 所以問題是因為微信的服務端在解釋multipart/form-data格式的時候,沒有考慮到這種值帶雙引號的情況的(multipart/form-data格式請自行谷歌百度),而使用.net core 的MultipartFormDataContent類,默認會在boundary參數值加雙引號。 問題終于真相大白了,所以接下來很簡單,修改一下MultipartFormDataContent的Content-Type,重新提交,上傳文件成功! 最終代碼如下:
public BaseResult uploadFile ( string path
, byte [ ] fileBuff
) { string resultContent
= "" ; try { var uploadFilePathResult
= getUploadFilePath ( path
) ; using ( HttpClient client
= new HttpClient ( ) ) { string boundary
= "-----------" + DateTime
. Now
. Ticks
. ToString ( "x" ) ; var formContent
= new MultipartFormDataContent ( boundary
) ; formContent
. Add ( new StringContent ( path
) , "\"key\"" ) ; formContent
. Add ( new StringContent ( uploadFilePathResult
. authorization
) , "\"Signature\"" ) ; formContent
. Add ( new StringContent ( uploadFilePathResult
. token
) , "\"x-cos-security-token\"" ) ; formContent
. Add ( new StringContent ( uploadFilePathResult
. cos_file_id
) , "\"x-cos-meta-fileid\"" ) ; var fileContent
= new ByteArrayContent ( fileBuff
) ; fileContent
. Headers
. ContentDisposition
= new System. Net. Http. Headers. ContentDispositionHeaderValue ( "form-data" ) { Name
= "\"file\"" , FileName
= "\"userlist.csv\"" } ; fileContent
. Headers
. ContentType
= new System. Net. Http. Headers. MediaTypeHeaderValue ( "text/csv" ) ; formContent
. Add ( fileContent
) ; formContent
. Headers
. Remove ( "Content-Type" ) ; formContent
. Headers
. Add ( "Content-Type" , "multipart/form-data; boundary=" + boundary
) ; var r
= client
. PostAsync ( uploadFilePathResult
. url
, formContent
) . Result
; var resultContentTask
= r
. Content
. ReadAsStringAsync ( ) ; resultContentTask
. Wait ( ) ; resultContent
= resultContentTask
. Result
; } } catch ( Exception e
) { } var result
= JsonConvert
. DeserializeObject < BaseResult > ( resultContent
) ; return result
; }
總結
以上是生活随笔 為你收集整理的记一次.net core调用微信云开发Http Api的uploadFile,上传文件到云环境的坑爹的排错过程 的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網站內容還不錯,歡迎將生活随笔 推薦給好友。