提前閱讀
四種常見post提交資料方式
理解http之Content-Type
情況描述
- content-type 為 x-www-form-urlencoded,但body非key1=value1&key2=value2的格式
- 服務端使用是jfinal 2.X
- Postman 模擬引數為
POST /api/rest/service/test HTTP/1.1
Host: v2.ynpay.cc
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
Postman-Token: 01e4d8f6-6e8c-c5a3-0672-80da11cdf322
<OrderProcessRequest xsi="http://www.w3.org/2001/XMLSchema-instance">
<Authentication>
<TimeStamp>2017-09-19 12:18:35</TimeStamp>
<ServiceName>web.order.lockOrder</ServiceName>
<MessageIdentity>testtest</MessageIdentity>
</Authentication>
<OrderService>
<OrderInfo>
<Number>1001</Number>
</OrderInfo>
</OrderService>
</OrderProcessRequest>複製程式碼
- 使用request.inputStream 從流裡獲取資料轉化為String 為空,在控制檯檢視 request.inputStream.request.parseFromData裡能看到資料。
- 使用request.parameterMap 可以獲取到資料,但資料格式有問題。
問題原因
根據selvet規範當遇到content-type為x-www-form-urlencoded,各個容器遵循了規範把post資料解析為parameter
自己的理解
- delete,get請求沒有body。
- put,post請求可以有但不一定非要有body
- 一般來說,body裡的資料都可以通過原始輸入流(inputstream)讀取再轉化為對應的物件(java中字串屬於物件)。
- content-type 只是規定了瀏覽器和伺服器解析請求的方式,和傳輸的內容無關,但是和傳輸內容的格式有關,瀏覽器和伺服器根據content-type的標準格式,去解析內容,如果指定錯content-type,則不一定能夠正確解析資料。
- content-type為x-www-form-urlencoded,如果嚴格按照標準格式,body裡面提交的引數也應該是key1=value1&key2=value2的形式。
解決方案
- 請求方的content-type 和body 內容的格式不匹配,但是在服務端接收到之前,servlet已經按照content-type 的標準方式去讀取了資料,所以想要在接收時強制改變content-type 也是不可行的。只能把解析出錯的資料,想辦法解析回原始傳遞的資料。
// kotlin 語法 var str = IOUtils.toString(request.inputStream) if (str.isNullOrBlank()) { str =request.parameterMap.map { entity -> (entity.value as Array<*>).map { "${entity.key}=$it" }.joinToString("&") }.joinToString("&") }複製程式碼