99网
您的当前位置:首页四种常见的POST提交数据方式专题

四种常见的POST提交数据方式专题

来源:99网
四种常见的POST提交数据⽅式专题

定义和⽤法

enctype 属性规定在发送到服务器之前应该如何对表单数据进⾏编码。

默认地,表单数据会编码为 \"application/x-www-form-urlencoded\"。就是说,在发送到服务器之前,所有字符都会进⾏编码(空格转换为 \"+\" 加号,特殊符号转换为 ASCII HEX值)。

enctype属性值

不对字符编码。

multipart/form-data

在使⽤包含⽂件上传控件的表单时,必须使⽤该值。

text/plain

规定的 HTTP 请求⽅法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这⼏种。其中 POST ⼀般⽤来向服务端提交数据,本⽂主要讨论 POST 提交数据的⼏种⽅式。我们知道,HTTP 协议是以 ASCII 码传输,建⽴在 TCP/IP 协议之上的应⽤层规范。规范把 HTTP 请求分为三个部分:状态⾏、请求头、消息主体。类似于下⾯这样:

BASH

描述

application/x-www-form-urlencoded在发送前编码所有字符(默认)

空格转换为 \"+\" 加号,但不对特殊字符编码。

协议规定 POST 提交的数据必须放在消息主体(entity-body)中,但协议并没有规定数据必须使⽤什么编码⽅式。实际上,开发者完全可以⾃⼰决定消息主体的格式,只要最后发送的 HTTP 请求满⾜上⾯的格式就可以。

但是,数据发送出去,还要服务端解析成功才有意义。⼀般服务端语⾔如 php、python 等,以及它们的 framework,都内置了⾃动解析常见数据格式的功能。服务端通常是根据请求头(headers)中的 Content-Type 字段来获知请求中的消息主体是⽤何种⽅式编码,再对主体进⾏解析。所以说到 POST 提交数据⽅案,包含了 Content-Type 和消息主体编码⽅式两部分。下⾯就正式开始介绍它们。

application/x-www-form-urlencoded

这应该是最常见的 POST 提交数据的⽅式了。浏览器的原⽣

表单,如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded ⽅式提交数据。

First name:

Last name:

此时Form提交的请求数据,抓包时看到的请求会是这样的内容(⽆关的请求头在本⽂中都省略掉了):

BASHPOST http://www.example.com HTTP/1.1 Content-Type: application/x-www-form-urlencoded;charset=utf-8 title=test&sub%5B%5D=1&sub%5B%5D=2&sub%5B%5D=3

⾸先,Content-Type 被指定为 application/x-www-form-urlencoded;其次,提交的数据按照 key1=val1&key2=val2 的⽅式进⾏编码,key 和 val 都进⾏了 URL 转码。⼤部分服务端语⾔都对这种⽅式有很好的⽀持。例如 PHP 中,$_POST['title'] 可以获取到 title 的值,$_POST['sub'] 可以得到 sub 数组。很多时候,我们⽤ Ajax 提交数据时,也是使⽤这种⽅式。

例如 和 的 Ajax,Content-Type 默认值都是「application/x-www-form-urlencoded;charset=utf-8」。

multipart/form-data

这⼜是⼀个常见的 POST 数据提交的⽅式。我们使⽤表单上传⽂件时,必须让

表单的enctype 等于 multipart/form-data。直接来看⼀个请求⽰例:

BASHPOST http://www.example.com HTTP/1.1

Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA------WebKitFormBoundaryrGKCBY7qhFd3TrwAContent-Disposition: form-data; name=\"text\"

title

------WebKitFormBoundaryrGKCBY7qhFd3TrwA

Content-Disposition: form-data; name=\"file\"; filename=\"chrome.png\"Content-Type: image/png

PNG ... content of chrome.png ...

------WebKitFormBoundaryrGKCBY7qhFd3TrwA--

这个例⼦稍微复杂点。⾸先⽣成了⼀个 boundary ⽤于分割不同的字段,为了避免与正⽂内容重复,boundary 很长很复杂。然后 Content-Type ⾥指明了数据是以 multipart/form-data 来编码,本次请求的 boundary 是什么内容。消息主体⾥按照字段个数⼜分为多个结构类似的部分,每部分都是以 --boundary 开始,紧接着是内容描述信息,然后是回车,最后是字段具体内容(⽂本或⼆进制)。如果传输的是⽂件,还要包含⽂件名和⽂件类型信息。消息主体最后以 --boundary-- 标⽰结束。关于 multipart/form-data 的详细定义,请前往 查看。

这种⽅式⼀般⽤来上传⽂件,各⼤服务端语⾔对它也有着良好的⽀持。

上⾯提到的这两种 POST 数据的⽅式,都是浏览器原⽣⽀持的,⽽且现阶段标准中原⽣ 表单也(通过 元素的 enctype 属性指定,默认为 application/x-www-form-urlencoded。其实 enctype 还⽀持 text/plain,不过⽤得⾮常少)。

随着越来越多的 Web 站点,尤其是 WebApp,全部使⽤ Ajax 进⾏数据交互之后,我们完全可以定义新的数据提交⽅式,给开发带来更多便利。

application/json

application/json 这个 Content-Type 作为响应头⼤家肯定不陌⽣。实际上,现在越来越多的⼈把它作为请求头,⽤来告诉服务端消息主体是序列化后的 JSON 字符串。由于JSON 规范的流⾏,除了低版本 IE 之外的各⼤浏览器都原⽣⽀持 JSON.stringify,服务端语⾔也都有处理 JSON 的函数,使⽤ JSON 不会遇上什么⿇烦。

JSON 格式⽀持⽐键值对复杂得多的结构化数据,这⼀点也很有⽤。记得我⼏年前做⼀个项⽬时,需要提交的数据层次⾮常深,我就是把数据 JSON 序列化之后来提交的。不过当时我是把 JSON 字符串作为 val,仍然放在键值对⾥,以 x-www-form-urlencoded ⽅式提交。Google 的 中的 Ajax 功能,默认就是提交 JSON 字符串。例如下⾯这段代码:

JSvar data = {'title':'test', 'sub' : [1,2,3]};

$http.post(url, data).success(function(result) { ...});

最终发送的请求是:

BASHPOST http://www.example.com HTTP/1.1 Content-Type: application/json;charset=utf-8{\"title\":\"test\1,2,3]}

这种⽅案,可以⽅便的提交复杂的结构化数据,特别适合 RESTful 的接⼝。各⼤抓包⼯具如 Chrome ⾃带的开发者⼯具、Firebug、Fiddler,都会以树形结构展⽰ JSON 数据,⾮常友好。但也有些服务端语⾔还没有⽀持这种⽅式,例如 php 就⽆法通过 $_POST 对象从上⾯的请求中获得内容。这时候,需要⾃⼰动⼿处理下:在请求头中 Content-Type为 application/json 时,从 php://input ⾥获得原始输⼊流,再 json_decode 成对象。⼀些 php 框架已经开始这么做了。当然 AngularJS 也可以配置为使⽤ x-www-form-urlencoded ⽅式提交数据。如有需要,可以参考。

text/xml

我的博客之前(XML Remote Procedure Call)。它是⼀种使⽤ HTTP 作为传输协议,XML 作为编码⽅式的远程调⽤规范。典型的 XML-RPC 请求是这样的:

HTMLPOST http://www.example.com HTTP/1.1 Content-Type: text/xml

examples.getStateName

41

XML-RPC 协议简单、功能够⽤,各种语⾔的实现都有。它的使⽤也很⼴泛,如 WordPress 的 ,搜索引擎的 等等。JavaScript 中,也有⽀持以这种⽅式进⾏数据交互,能很好的⽀持已有的 XML-RPC 服务。不过,我个⼈觉得 XML 结构还是过于臃肿,⼀般场景⽤ JSON 会更灵活⽅便。

最近为项⽬组提供rest api 时遇到了关于接⼝参数的传递问题,主要是没有充分考虑到第三⽅调⽤者的使⽤⽅式,应该尽量的去兼容公司之前提供出去的接⼝调⽤⽅式,这样可以降低第三⽅调⽤者的学习成本,尽管之前的⽅式并不是那么的推荐,好的做法是即兼容⽼的做法也⽀持推荐的做法。

对于基于http post接⼝,Content-type我会优先选择application/json,但公司之前提供的接⼝恰恰采⽤了application/x-www-form-urlencoded,它是表单默认的提交类型,基于key/value形式提交到服务端的。

spring mvc是如何接收下⾯两种经典数据的? (⾄于form-data,它即可以传键值对也可以上传⽂件,这⾥不涉及到⽂件所以只讨论下⾯两种):

Content-type=application/json:需要在参数上增加@RequestBody这个注解,说明参数是从http的requestbody中获取。

下图中的参数,是标准的json格式,对前端js⾮常友好。

Content-type=application/x-www-form-urlencoded,参数上不能增加@RequestBody的注解下图的可以看出参数形式与get请求时,URL后⾯的参数格式

为什么不推荐采⽤application/x-www-form-urlencoded这种类型,它有如下问题:

测试困难,就别想通过postman这类⼯具测试:提交到服务端实际上是⼀个MultiValueMap(org.springframework.util.MultiValueMap或org.springframework.util.LinkedMultiValueMap),

如果value中的对象也是⼀个对象,那么在构建这个参数时就⾮常困难,看下它的过程

采⽤key1=value1&key2=value2这种形式将所有参数拼接起来,从⼀长串字符中想了解每个参数的含义没有个好眼⼒怕是不⾏。value要进⾏编码,编码之后的对调试者不友好。

value是复杂对象的情况更加糟糕,⼀般只能通过程序来序列化得到参数,想⼿写基本不可能。客户端调⽤复杂

需要去构建List,⼀般页⾯传递的参数都是⼀个实体对象Model,需要额外的将这个Model转换成List,如果这个对象复杂,那么构建这个Key/Value就够⼈烦的了。

这⾥给⼀个java通过apache httpclient调⽤的对⽐,看看哪⼀个简单。

application/x-www-form-urlencoded需要⼿⼯将model转换成NameValuePair。

application/json

这⾥只需要Model即可,不需要⼆次转换,结构也⾮常清楚。

key/value的语⾔表达形式没有json强,下⾯两种你更加喜欢哪⼀个呢?字符串

post man这类模似http请求的⼯具中,如果key对应的value是个对象,那么你需要通过⼯具得到它的序列化之后的字符串然后填写到字段中,想想都烦。如果你说我不需要通过这些模似⼯具测试,那就另当别论

json

数据结构更加复杂

如果需要提交的对象⾮常复杂,属性⾮常多,如果将所有的属性都构建到MultiValueMap中,那个Map的构建会⾮常复杂,试想如果对象有多级嵌套对象呢。所有为了避免这个问题,我们将需要提交的业务对象做为⼀个key来存储,value就是对象序列化之后的字符串。再加了⼀些⾮业务参数,⽐如安全⽅⾯的token等参数,有效的降低了MultiValueMap构建的复杂度。但这种⽅式相对于json的传递⽅式来讲层次更深。如下图,我们的参数多了⼀层,jsonParam。

如果解决呢?

不能不兼容现有的模式,但⼜想⽀持json,焦点就是在参数的接收上,让其能够完美的兼容上述两种参数传递,这⾥可以从HttpMessageConverter着⼿,这个就是⽤来将请求的参数映射到spring mvc⽅法中的实体参数的。我们可以编写⼀个⾃定义的类,内部借⽤FormHttpMessageConverter来接收MultiValueMap,即使⽅法参数上增加了@RequestBody的注解,也会⾛我们⾃定义的converter,就有机会去重新给参数赋值。

这个⽅法中需要解决⼀个问题,就是客户端传递时每个参数都是当成字符串来处理的,这种导致我们通过FormHtppMessageConverter转换成Map时,原本是对象的属性被识别成字符串,⽽不是object,结果就是在反序列化时会出错。好在,上⾯我们将需要提交的对象包装了⼀次,产⽣⼀个公共的object参数jsonParam,只需要处理这⼀个特殊对象。做法就是从Map取出jsonParam,然后对其内容进⾏反序列化,更新Map值,再次进⾏反序列化就正常了。

上图中的做法⽬前有如下问题

序列化的字段是约定好的,也是基于我们的post model基本上来处理的,是针对性的converter

代码最后⾯调⽤的jackon的convertValue,对需要反序列化的对象类型有要求,好像不⽀持泛型类型,⽐如这种类型的就不⾏:CommonParamInfoDto>

完整的conveter代码如下,其实主要代码就是上图贴图中的那么对特定字段的序列化处理,其它的⽅法都是默认即可。

public class ObjectHttpMessageConverter implements HttpMessageConverter {

private final FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); private final ObjectMapper objectMapper = new ObjectMapper();

private static final LinkedMultiValueMap LINKED_MULTI_VALUE_MAP = new LinkedMultiValueMap<>(); private static final Class> LINKED_MULTI_VALUE_MAP_CLASS = (Class>) LINKED_MULTI_VALUE_MAP.getClass();

@Override

public boolean canRead(Class clazz, MediaType mediaType) {

return objectMapper.canSerialize(clazz) && formHttpMessageConverter.canRead(MultiValueMap.class, mediaType); }

@Override

public boolean canWrite(Class clazz, MediaType mediaType) { return false; }

@Override

public List getSupportedMediaTypes() {

return formHttpMessageConverter.getSupportedMediaTypes(); }

@Override

public Object read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { Map input = formHttpMessageConverter.read(LINKED_MULTI_VALUE_MAP_CLASS, inputMessage).toSingleValueMap(); String jsonParamKey=\"jsonParam\"; if(input.containsKey(jsonParamKey)) {

String jsonParam = input.get(jsonParamKey).toString();

SearchParamInfo searchParamInfo = new SearchParamInfo();

Object jsonParamObj = JsonHelper.json2Object(jsonParam, searchParamInfo.getClass()); input.put(\"jsonParam\ }

Object objResult= objectMapper.convertValue(input, clazz); return objResult; }

@Override

public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws UnsupportedOperationException { throw new UnsupportedOperationException(\"\"); }}

配置,写好了conveter之后,需要在配置⽂件中配置上才能⽣效。

最后,我们的⽅法就可以这样写,即可以⽀持 key/value对,也⽀持json

我的⽬的在于api的参数即能⽀持application/x-www-form-urlencoded也能⽀持application/json,上⾯是我⽬前能想到的办法,如果⼤家有其它更好的办法多多指点。根据上⾯的描述,可以得到以下结论:

对象将转换成什么样的内容类型很⼤程序上取决于传递给put⽅法的类型,

如果给定⼀个String值,那么将会使⽤StringHttpMessageConverter,这个值直接被写到请求体中,内容类型设置为\"text/plain\"

如果给定⼀个MultiValueMap,那么这个Map中的值会被FormHttpMessageConverter以“application/x-www-form-urlencoded”的格式写到请求体中因为给定的是⼀个⾃定义对象,所以需要⼀个能够处理任意对象的信息转换器。如果在类路径下包含Jackson2库,那么MappingJacksonHttpMessageConverter将以application/json格式将⾃定义对象写到请求中

我⼜可以愉快的使⽤post man测试了。⽽且可以推荐第三⽅调⽤者优先使⽤json,我相信这种即能简化编程⼜⽅便调试的优点应该能够吸引它们。

postman中 form-data、x-www-form-urlencoded、raw、binary的区别

1、form-data:

就是http请求中的multipart/form-data,它会将表单的数据处理为⼀条消息,以标签为单元,⽤分隔符分开。既可以上传键值对,也可以上传⽂件。当上传的字段是⽂件时,会有Content-Type来表名⽂件类型;content-disposition,⽤来说明字段的⼀些信息;

由于有boundary隔离,所以multipart/form-data既可以上传⽂件,也可以上传键值对,它采⽤了键值对的⽅式,所以可以上传多个⽂件。新版本Postman在此处查看:

2、x-www-form-urlencoded:

就是application/x-www-from-urlencoded,会将表单内的数据转换为键值对,⽐如,name=java&age = 23

3、raw

可以上传任意格式的⽂本,可以上传text、json、xml、html等

4、binary

相当于Content-Type:application/octet-stream,从字⾯意思得知,只可以上传⼆进制数据,通常⽤来上传⽂件,由于没有键值,所以,⼀次只能上传⼀个⽂件。

multipart/form-data与x-www-form-urlencoded区别

multipart/form-data:既可以上传⽂件等⼆进制数据,也可以上传表单键值对,只是最后会转化为⼀条信息;x-www-form-urlencoded:只能上传键值对,并且键值对都是间隔分开的。

上传⽂件的表单中要加属性enctype=\"multipart/form-data\很多⼈只是死记硬背知道上传表单要这么 写,知其然⽽不知其所以然。那到底为什么要添加这个属性呢?它是什么意思呢?它⼜有什么其他可选值呢? 其实form表单在你不写enctype属性时,也默认为其添加了enctype属性值,默认值是enctype=\"application/x- www-form-urlencoded\".这个属性管理的是表单的MIME编码,共有三个值可选:  ①application/x-www-form-urlencoded (默认值)  ②multipart/form-data  ③text/plain

  其中①application/x-www-form-urlencoded是默认值,⼤家可能在AJAX⾥见过这 个:xmlHttp.setRequestHeader(\"Content-Type\这两个要做的是同⼀件事情,就是设置表单传输的编码。在AJAX⾥不写有可能会报错,但是在HTML的form表单⾥是可以不写 enctype=\"application/x-www-form-urlencoded\"的,因为默认HTML表单就是这种传输编码类型。⽽ ②multipart-form-data是⽤来指定传输数据的特殊类型的,主要就是我们上传的⾮⽂本的内容,⽐如图⽚或者mp3等等。

③text/plain是纯⽂本传输的意思,在发送邮件时要设置这种编码类型,否则会出现接收时编码混乱的问题,⽹络上经常拿text/plain和 text/html做⽐较,其实这两个很好区分,前者⽤来传输纯⽂本⽂件,后者则是传递html代码的编码类型,在发送头⽂件时才⽤得上。①和③都不能⽤ 于上传⽂件,只有multipart/form-data才能完整的传递⽂件数据。  上⾯提到的MIME,它的英⽂全称是\"Multipurpose Internet Mail Extensions\" 多功能Internet 邮件扩充服务,它是⼀种多⽤途⽹际邮件扩充协议,在1992年最早应⽤于电⼦邮件系统,但后来也应⽤到浏览器。服务器会将它们发送的多媒体数据的类型告诉 浏览器,⽽通知⼿段就是说明该多媒体数据的MIME类型,从⽽让浏览器知道接收到的信息哪些是MP3⽂件,哪些是Shockwave⽂件等等。服务器将 MIME标志符放⼊传送的数据中来告诉浏览器使⽤哪种插件读取相关⽂件。

  简单说,MIME类型就是设定某种扩展名的⽂件⽤⼀种应⽤程序来打开的⽅式类型,当该扩展名⽂件被访问的时候,浏览器会⾃动使⽤指定应⽤程序来打开。多⽤于指定⼀些客户端⾃定义的⽂件名,以及⼀些媒体⽂件打开⽅式。

  浏览器接收到⽂件后,会进⼊插件系统进⾏查找,查找出哪种插件可以识别读取接收到的⽂件。如果浏览器不清楚调⽤哪种插件系统,它可能会告诉⽤户缺少某 插件,或者直接选择某现有插件来试图读取接收到的⽂件,后者可能会导致系统的崩溃。传输的信息中缺少MIME标识可能导致的情况很难估计,因为某些计算机 系统可能不会出现什么故障,但某些计算机可能就会因此⽽崩溃。

检查⼀个服务器是否正确设置了MIME类型的步骤是:

  1. 在Netscape浏览器中打开服务器⽹页  2. 进⼊\"View\"菜单,选择\"Page Info\"

  3. 在弹出的窗⼝中点击上层框架中的\"EMBED\"

  4. 在下层框架中查看MIME的类型是否为\"application/x-director\"或\"application/x-shockwave- flash\",如果是上述信息的话表明服务器已经正确设置了MIME类型; ⽽如果MIME类型列出的是⽂本内容、⼋位⼀组的数据或是其它形式均表明服务器 的MIME类型没有设置正确。  如果服务器没有正确标明其发送的数据的类型,服务器管理员应该正确添加相关信息,具体操作⽅法⾮常简单快捷。  每个MIME类型由两部分组成,前⾯是数据的⼤类别,例如声⾳audio、图象image等,后⾯定义具体的种类。  常见的MIME类型

    超⽂本标记语⾔⽂本 .html,.html text/html    普通⽂本 .txt text/plain    RTF⽂本 .rtf application/rtf

    GIF图形 .gif image/gif

    JPEG图形 .jpeg,.jpg image/jpeg    au声⾳⽂件 .au audio/basic

    MIDI⾳乐⽂件 mid,.midi audio/midi,audio/x-midi    RealAudio⾳乐⽂件 .ra, .ram audio/x-pn-realaudio    MPEG⽂件 .mpg,.mpeg video/mpeg    AVI⽂件 .avi video/x-msvideo    GZIP⽂件 .gz application/x-gzip    TAR⽂件 .tar application/x-tar

Internet中有⼀个专门组织IANA来确认标准的MIME类型,但Internet发展的太快,很多应⽤程序等不及IANA来确认他们使⽤ 的MIME类型为标准类型。因此他们使⽤在类别中以x-开头的⽅法标识这个类别还没有成为标准,例如:x-gzip,x-tar等。事实上这些类型运⽤的 很⼴泛,已经成为了事实标准。只要客户机和服务器共同承认这个MIME类型,即使它是不标准的类型也没有关系,客户程序就能根据MIME类型,采⽤具体的 处理⼿段来处理数据。⽽Web服务器和浏览器(包括操作系统)中,缺省都设置了标准的和常见的MIME类型,只有对于不常见的 MIME类型,才需要同时设置服务器和客户浏览器,以进⾏识别。----------------------------------------------------------------表单中enctype=\"multipart/form-data\"的意思,是设置表单的MIME编码。默认情况,这个编码格式是application/x-www-form-urlencoded,不能⽤于⽂件上传;只有使⽤了multipart/form-data,才能完整的传递⽂件数据,进⾏下⾯的操作.

enctype=\"multipart/form-data\"是上传⼆进制数据; form⾥⾯的input的值以2进制的⽅式传过去。form⾥⾯的input的值以2进制的⽅式传过去,

所以request就得不到值了。也就是说加了这段代码,⽤request就会传递不成功,取表单值加⼊数据库时,⽤到下⾯的:

SmartUpload su = new SmartUpload();//新建⼀个SmartUpload对象su.getRequest().getParameterValues();取数组值su.getRequest().getParameter( );取单个参数单个值

ajax中的application/x-www-form-urlencoded中的使⽤

⼀,HTTP上传的基本知识

在Form元素的语法中,EncType表明提交数据的格式 ⽤ Enctype 属性指定将数据回发到服务器时浏览器使⽤的编码类型。下边是说明: application/x-www-form-urlencoded:窗体数据被编码为名称/值对。这是标准的编码格式。 multipart/form-data: 窗体数据被编码为⼀条消息,页上的每个控件对应消息中的⼀个部分。 text/plain:窗体数据以纯⽂本形式进⾏编码,其中不含任何控件或格式字符。补充

form的enctype属性为编码⽅式,常⽤有两种:application/x-www-form-urlencoded和multipart/form-data,默认为application /x-www-form-urlencoded。

当action为get时候,浏览器⽤x-www-form-urlencoded的编码⽅式把form数据转换成⼀个字串(name1=value1& amp; amp;name2=value2...),然后把这个字串append到url后⾯,⽤?分割,加载这个新的url。

当action为post时候,浏览器把form数据封装到http body中,然后发送到server。

如果没有type=file的控件,⽤默认的application/x-www-form-urlencoded就可以了。但是如果有 type=file的话,就要⽤到multipart/form-data了。

浏览器会把整个表单以控件为单位分割,并为每个部分加上 Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件 name)等信息,并加上分割符(boundary)。

⼆,使⽤中需要注意的地⽅

在AJAX往服务器上传数据是,设置了content-type为application/x-www-form-urlencoded,此时是对整个发 送内容作了编码,并不是对名字对应的值做了编码。因此,在服务器端,通过request.getParameter(\"name\")的⽅式取值,是有问题 的。有两种解法办法:

1)改服务器端: 采⽤流的⽅式硬编码

InputStream stream=request.getInputStream();

InputStreamReader isr=new InputStreamReader(stream);BufferedReader br=new BufferedReader(isr);String str=br.readLine(); System.out.println(str);

str=URLDecoder.decode(str,\"gb2312\");System.out.println(str);br.close();

2)改客户端:更改数据发送结构

在往服务器上发数据的时候,使⽤name=escape(value)的⽅式组对

此时在服务器代码中,通过request.getParameter(\"name\")获得的数值,就不⽤编码了application/x-www-form-urlencoded、multipart/form-data、text/plain

org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'multipart/form-data;boundary=----WebKitFormBoundaryRAYPKeHKTYSNdzc1;charset=UTF-8'not supported

最近同事在做⼀个图⽚上传功能、在⼊参 body 中同时传⼊⽂件和其它基本信息结果出现如题异常、在此记录下解决办法、以做记录。controller 代码如下:

@RequestMapping(value = \"/upload\@ResponseBody

public String upload(@RequestParam(\"file\") MultipartFile file, @RequestBody User user) {// 业务处理............}

在使⽤⼯具测试(Postman、 swagger )时报如下异常

\"timestamp\": 1473349676109, \"status\": 415,

\"error\": \"Unsupported Media Type\

\"exception\": \"org.springframework.web.HttpMediaTypeNotSupportedException\

\"message\": \"Content type 'multipart/form-data;boundary=----WebKitFormBoundaryTVc9eDC2a2elulOx;charset=UTF-8' not supported\ \"path\": \"/upload\"

解决⽅案:

关键词:理解 http 消息头

使⽤ multipart form-data 上传 ⽂件

以前的章节已经介绍过了form传输表单的形式,但是在使⽤过程中仍然有很多问题,这⾥再向⼤家详细介绍⼀下。

multipart/form-data是上传⽂件的⼀种⽅式。multipart/form-data其实就是浏览器⽤表单上传⽂件的⽅式。

最常见的情境是:在写邮件时,向邮件后添加附件,附件通常使⽤表单添加,也就是⽤multipart/form-data格式上传到服务器。具体的步骤如下:

1、客户端和服务器建⽴链接(tcp协议)2、客户端可以向服务器发送数据

3、客户端按照符合multipart/form-data的格式发送数据

post /top/router/rest ?timestamp=2013-05-24%2010%3a14%3a48&method=taobao.item.update&title=title%20998&session=610231517b65e4e4e82575817e2d9169eeaac271cb91c55378591009&app_key=10011050&v=2.0&num_iid=130688on&sign=6570c00315a94edac47414b6e9b681e0 http/1.0

content-type: multipart/form-data; boundary=------webkitformboundaryx3mhup4uhvo8zy3oaccept-charset: utf-8host: gw.api.taobao.comconnection: closecontent-length: 58294

--------webkitformboundaryx3mhup4uhvo8zy3o

content-disposition: form-data; name=\"image\"; filename=\"path\\ddd.jpg\"content-type: image/gif

......jfif.............c..................................省略的图⽚⽂件信息 --------webkitformboundaryx3mhup4uhvo8zy3o--解释说明

content-type: multipart/form-data; boundary=------webkitformboundaryx3mhup4uhvo8zy3o 说明的是multipart/form-data格式的请求,boundary是⼀个字符串,⽤来切分数据。

仔细查看,会发现body⾥⾯的bounday⽐header⾥⾯的前⾯都多了“--”。这是⼀个坑,我被搬到过。需要注意的是,在html协议中换⾏使⽤的是:\"\\r\\n\",这我也被绊倒过。下⾯是lua拼写的上传服务器的代码:

body = \"--------webkitformboundaryx3mhup4uhvo8zy3o\\r\\ncontent-disposition: form-data; name=\\\"image\\\"; filename=\\\"path\\\\ddd.jpg\\\"\\r\\ncontent-type: image/gif\\r\\n\\r\\n\" .. body;body = body .. \"\\r\\n--------webkitformboundaryx3mhup4uhvo8zy3o--\\r\\n\";

postman进⾏访问服务器时,使⽤浏览器的url可以正常返回结果,但是postman却显⽰Could not get any response

Could not get any response

This seems to be like an error connecting to http://pc.oma.com:9090/oma/venue/updateVenue. Why this might have happened:

The server couldn't send a response:

Ensure that the backend is working properly SSL connections are being blocked:

Fix this by importing SSL certificates in Chrome Cookies not being sent:

Use the Postman Interceptor extension Request timeout:

Change request timeout in Settings > General

解决办法:

因篇幅问题不能全部显示,请点此查看更多更全内容