post 提交 x-www-form-urlencoded 方式 inputStream 為空

大臉貓大臉貓愛吃魚發表於2017-09-19

提前閱讀

四種常見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

自己的理解

  1. delete,get請求沒有body。
  2. put,post請求可以有但不一定非要有body
  3. 一般來說,body裡的資料都可以通過原始輸入流(inputstream)讀取再轉化為對應的物件(java中字串屬於物件)。
  4. content-type 只是規定了瀏覽器和伺服器解析請求的方式,和傳輸的內容無關,但是和傳輸內容的格式有關,瀏覽器和伺服器根據content-type的標準格式,去解析內容,如果指定錯content-type,則不一定能夠正確解析資料。
  5. 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("&")
          }複製程式碼

相關文章