HTTP請求頭中的Content-type對資料的影響-Android
最近幾天有點鬱悶,不是因為別人,而是覺得自己做開發兩年時間了,有些基本的東西還是模模糊糊的,導致工作過程在非常被動,而且效率不太如意,公司最近做一個專案,需要跟其它公司的後臺做對接,不得不說,後臺不在自己公司,對接起來效率真的低很多!下面說下問題!
一、首先,下面是介面文件
我們看到是post請求,引數會全部轉換成json的形式,key為content,而我用的是okhttp這個網路框架,所以就有了下面的程式碼
public void getBody(String json){ FormBody.Builder bodyF = new FormBody.Builder(); bodyF.add("content",json); RequestBody body= bodyF.build(); }
注:其實一開始我就錯了,上面的content的壓根就不是指key,content其實就直接是json串了,自己粗心大意導致了後面的問題出現不過問題既然出現了,那就順便研究研究吧。
2、到了這裡,就風風火火的發起網路請求了,然後也訪問介面成功了,只不過問題出現了後臺出現的json資料變成了下面這個樣子,導致無法解析
緊接著後臺就說是我編碼不是UTF-8導致出現亂碼,可是我一想不對啊,我的資料沒有中文,後來嘗試了各種方法也不行,最後嘗試了下URLDecoder.decode(str,"UTF-8"),結果還真還原了資料,至此終於明白了,原來資料是被編碼了,可是自己明明沒有做編碼的操作content=%7B%22content%22%3A%7B%22DataOfObuVehInfo%22%3A%7B%22obuNo%22%3A%2212365953249256354872%22%2C%22posTSN% 22%3A0%2C%22randomForMAC%22%3A%5B49%2C50%2C51%2C52%2C53%2C54%2C55%2C56%2C57%5D%7D%2C%22channelType%22%3A%22fjetc %22%2C%22charset%22%3A%2202%22%2C%22deviceID%22%3A%2213828899271%22%2C%22deviceType%22%3A%22phone%22%2C%22 merchantId%22%3A%2290812241%22%2C%22notifyUrl%22%3A%22http%3A%2F%2F
檢視FormBody的add方法終於發現,原來資料add進去後是經過了編碼的
public FormBody.Builder add(String name, String value) { if (name == null) throw new NullPointerException("name == null"); if (value == null) throw new NullPointerException("value == null"); names.add(HttpUrl.canonicalize(name, FORM_ENCODE_SET, false, false, true, true, charset)); values.add(HttpUrl.canonicalize(value, FORM_ENCODE_SET, false, false, true, true, charset)); return this; }
是在coanonicalize方法中做的
3、到了這裡,後臺的哥們也不錯,屁顛屁顛的就把資料給做了解碼操作(其實真的是我這邊的問題。。。),不過先不管了,一切以實現功能為主,至於怎麼實現、想能優化,那都是後續的問題!本來以為這就沒事了,誰知道,緊接著後臺又說資料解析不通過,前面多了個content=,如下的資料:
content={"a":"xxx","b":"xxx"...}所以解析不了
ok,看了下資料,多出來的部分分明就是傳遞引數的時候的key,估計服務端是直接去讀流了,把body裡所有資料都讀出來了,而不是使用getParameter的方式去讀,沒辦法,只能換成如下方式去生成body public RequestBody getBody(String json){
RequestBody body= RequestBody.create(MediaType.parse("application/json;charset=utf-8"),json);
return body;
}
果然,換成這種方式之後,資料正常了,可是讓我豁然開朗的是,後臺的哥們跟我說,我改了之後資料沒有被編碼了,終於隱隱發覺,資料被自動編碼原來是跟application/json這個引數有關係,而這就是http裡面請求頭中的Content-type了。二、既然知道了是Content-type導致了剛才的問題,那麼就好好看下吧
其實在http協議規範中,post提交的資料是放在entity-body中的,但協議並沒有規定資料必須使用什麼編碼方式,實際上是由開發者去選擇的,只不過後臺也需要根據前端所選擇的編碼方式去解析。
1、application/x-www-form-urlencoded;charset=utf-8
檢視相關文件發現,這種Content-type型別是以form表單的形式提交資料的是基於uri的percent-encoding編碼的,所以body中的資料會以key=values的形式進行序列化,而這個編碼的過程中,一些特殊符號會通過URL轉碼轉成如4%D3%3F。。。等形式,這就導致了我們前面出現了json資料被做了這樣的處理,因為預設情況下okhttp的Content-type預設就是application/x-www-form-urlencoded,這就不難解析為什麼後臺以流的形式讀取資料的時候拿到的資料多了個content=,並且被編碼了。
2、application/json;charset=utf-8
這種Content-type的編碼方式現在是非常流行的,如果你在請求的時候使用抓包工具進行抓包,你會發現,請求體裡面顯示的內容是一個標準的json串,而不會像經過URL轉碼後的資料那樣。
好了,決絕了問題,也學到了些許新東西,希望對大家有些用!!