背景
Unity 5.6
官方參考手冊 2017.1
起因
項目中使用HTTP協(xié)議與服務(wù)端進行POST通信,傳輸?shù)臄?shù)據(jù)格式是文本。其中涉及到了base64編碼。
實際測試過程中,與服務(wù)端Log對比后發(fā)現(xiàn)。服務(wù)端接收到的Body內(nèi)的數(shù)據(jù)與客戶端發(fā)出的有所差別。差別處在于base64編碼后常見的=變成了%3d。而巧了,=字符的URL編碼正是%3d。
那么究竟是誰那么“好心”更改了數(shù)據(jù)呢?
解決
在使用百度搜索無果后,打開了不存在的網(wǎng)站Google,輸入Unity、HTTP、POST、URLEncode等關(guān)鍵字。終于尋找到了眉目
這個貼主遇到的是JSON序列化后的字符串也經(jīng)過了“更正”,盡管與我的base64問題并不完全一致,也算的上是受害伙伴了。
在回帖中,一位外國友人針對Unity的HTTP通信細節(jié)進行了詳細講解。

意思就是說,Unity的UnityWebRequest API會對POST方式中傳輸?shù)臄?shù)據(jù)進行內(nèi)部的URL編碼。
而解決方法則是,使用UnityWebRequest的PUT方式,(該方式不會對其進行URL編碼,傳輸?shù)氖荝awData)。在這之后手動將其傳輸方式更改為POST(如果你的服務(wù)端已制定用POST方式獲取數(shù)據(jù)的話)。
用偽代碼來說,就是:
//通過PUT方式構(gòu)造HTTP請求
byte[] myData = System.Text.Encoding.UTF8.GetBytes("This is some test data");
UnityWebRequest www = UnityWebRequest.Put("http://www.my-server.com/upload", myData);
//構(gòu)造好后,手動將請求方式更改為POST
www.method = UnityWebRequest.kHttpVerbPOST;
//常規(guī)的發(fā)送,接收操作
yield return www.Send();
if(www.isError) {
Debug.Log(www.error);
}
else {
Debug.Log("Upload complete!");
}
這樣便可解決題設(shè)問題了。
Another Solution
在方才引用的帖子中,還有一位外國友人提出了另一種異曲同工的方案。

這種UnityWebRequest的構(gòu)造方式,屬于Unity所說的the Low-Level API (LLAPI),是更底層的、可定制化的API。它為開發(fā)者提供了對上傳的數(shù)據(jù)體,HTTP請求的Header,下載的數(shù)據(jù)處理等更細粒度的控制。
而上述代碼的UnityWebRequest.Put抑或UnityWebRequest.Post則是HLAPI,只此一句便實現(xiàn)了URL的指定、請求方式的制定、Header和Body的構(gòu)建。這也是它對Body中的數(shù)據(jù)擅自進行URL編碼的根源。
圖中代碼需要對Body中的數(shù)據(jù)進行手動填充,自然也就解決了題設(shè)的問題了。
后記
Unity客戶端如果通過HTTP協(xié)議與服務(wù)端通信,采用的方案大致有三種:
- HttpWebRequest(C#原生,聽說使用很復(fù)雜)
- WWW
- UnityWebRequest
后兩種都是Unity實現(xiàn)封裝的API,而WWW由于在下載AssetBundle時的內(nèi)存占用兩倍的問題,已被官方擯棄,轉(zhuǎn)而推薦使用新的UnityWebRequest。
在受問題阻擾的過程中,我曾嘗試使用WWW的POST方式來進行通信。結(jié)果證明,WWW同樣對Body內(nèi)的數(shù)據(jù)進行了URL編碼。
也許WWW同樣有LLAPI可以對其進行更精細的掌控(未查證),然而由于UnityWebRequest是官方推薦的新方式,在此決定不再細究WWW。