提前阅读
四种常见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("&") }