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

定义和用法

enctype 属性规定在发送到服务器以前应该如何对表单数据进行编码
默认地,表单数据会编码为 "application/x-www-form-urlencoded"。就是说,在发送到服务器以前,全部字符都会进行编码(空格转换为 "+" 加号,特殊符号转换为 ASCII HEX 值)。php

enctype属性值

描述
application/x-www-form-urlencoded 在发送前编码全部字符(默认)
multipart/form-data

不对字符编码。html

在使用包含文件上传控件的表单时,必须使用该值。前端

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

 

HTTP/1.1 协议规定的 HTTP 请求方法有 OPTIONS、GET、HEAD、POST、PUT、DELETE、TRACE、CONNECT 这几种。
其中 POST 通常用来向服务端提交数据,本文主要讨论 POST 提交数据的几种方式。java

咱们知道,HTTP 协议是以 ASCII 码传输,创建在 TCP/IP 协议之上的应用层规范。
规范把 HTTP 请求分为三个部分:状态行、请求头、消息主体。相似于下面这样:python

BASH<method> <request-URL> <version>
<headers>

<entity-body>

协议规定 POST 提交的数据必须放在消息主体(entity-body)中,但协议并无规定数据必须使用什么编码方式。实际上,开发者彻底能够本身决定消息主体的格式,只要最后发送的 HTTP 请求知足上面的格式就能够。jquery

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

application/x-www-form-urlencoded

这应该是最多见的 POST 提交数据的方式了。浏览器的原生 <form> 表单,若是不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据。web

<form action="form_action.asp" enctype="text/plain"> <p>First name: <input type="text" name="fname" /></p> <p>Last name: <input type="text" name="lname" /></p> <input type="submit" value="Submit" /> </form>

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

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=3spring

首先,Content-Type 被指定为 application/x-www-form-urlencoded;其次,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。
大部分服务端语言都对这种方式有很好的支持。例如 PHP 中,$_POST['title'] 能够获取到 title 的值,$_POST['sub'] 能够获得 sub 数组。

不少时候,咱们用 Ajax 提交数据时,也是使用这种方式。
例如 JQuery 和 QWrap 的 Ajax,Content-Type 默认值都是「application/x-www-form-urlencoded;charset=utf-8」。

multipart/form-data

这又是一个常见的 POST 数据提交的方式。咱们使用表单上传文件时,必须让 <form> 表单的enctype 等于 multipart/form-data。直接来看一个请求示例:

BASHPOST http://www.example.com HTTP/1.1 Content-Type:multipart/form-data; boundary=----WebKitFormBoundaryrGKCBY7qhFd3TrwA ------WebKitFormBoundaryrGKCBY7qhFd3TrwA Content-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 的详细定义,请前往 rfc1867 查看。

这种方式通常用来上传文件,各大服务端语言对它也有着良好的支持。

上面提到的这两种 POST 数据的方式,都是浏览器原生支持的,并且现阶段标准中原生 <form> 表单也只支持这两种方式(经过 <form> 元素的 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 的 AngularJS 中的 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","sub":[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-RPC(XML Remote Procedure Call)。它是一种使用 HTTP 做为传输协议,XML 做为编码方式的远程调用规范。典型的 XML-RPC 请求是这样的:

复制代码
HTMLPOST http://www.example.com HTTP/1.1 
Content-Type: text/xml

<?xml version="1.0"?> <methodCall> <methodName>examples.getStateName</methodName> <params> <param> <value><i4>41</i4></value> </param> </params> </methodCall>
复制代码

XML-RPC 协议简单、功可以用,各类语言的实现都有。它的使用也很普遍,如 WordPress 的 XML-RPC Api,搜索引擎的 ping 服务等等。JavaScript 中,也有现成的库支持以这种方式进行数据交互,能很好的支持已有的 XML-RPC 服务。不过,我我的以为 XML 结构仍是过于臃肿,通常场景用 JSON 会更灵活方便。

https://imququ.com/post/four-ways-to-post-data-in-http.html

rest api参数与content-type

最近为项目组提供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<NameValuePair>,通常页面传递的参数都是一个实体对象Model,须要额外的将这个Model转换成List<NameValuePair>,若是这个对象复杂,那么构建这个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<SearchParamInfo<ProductSearchInfo>>

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

复制代码
public class ObjectHttpMessageConverter implements HttpMessageConverter<Object> { private final FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter(); private final ObjectMapper objectMapper = new ObjectMapper(); private static final LinkedMultiValueMap<String, ?> LINKED_MULTI_VALUE_MAP = new LinkedMultiValueMap<>(); private static final Class<? extends MultiValueMap<String, ?>> LINKED_MULTI_VALUE_MAP_CLASS = (Class<? extends MultiValueMap<String, ?>>) 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<MediaType> 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<Object> searchParamInfo = new SearchParamInfo<Object>(); Object jsonParamObj = JsonHelper.json2Object(jsonParam, searchParamInfo.getClass()); input.put("jsonParam", jsonParamObj); } 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<String,String>,那么这个Map中的值会被FormHttpMessageConverter以“application/x-www-form-urlencoded”的格式写到请求体中
由于给定的是一个自定义对象,因此须要一个可以处理任意对象的信息转换器。若是在类路径下包含Jackson2库,那么MappingJacksonHttpMessageConverter将以application/json格式将自定义对象写到请求中

 

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

http://www.cnblogs.com/ASPNET2008/p/5744815.html


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

一、form-data: 
就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既能够上传键值对,也能够上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来讲明字段的一些信息;
因为有boundary隔离,因此multipart/form-data既能够上传文件,也能够上传键值对,它采用了键值对的方式,因此能够上传多个文件。

新版本Postman在此处查看:

 


二、x-www-form-urlencoded:
就是application/x-www-from-urlencoded,会将表单内的数据转换为键值对,好比,name=java&age = 23

三、raw
能够上传任意格式的文本,能够上传text、json、xml、html等


 

四、binary
至关于Content-Type:application/octet-stream,从字面意思得知,只能够上传二进制数据,一般用来上传文件,因为没有键值,因此,一次只能上传一个文件。


multipart/form-data与x-www-form-urlencoded区别
multipart/form-data:既能够上传文件等二进制数据,也能够上传表单键值对,只是最后会转化为一条信息;
x-www-form-urlencoded:只能上传键值对,而且键值对都是间隔分开的。

http://blog.csdn.net/ye1992/article/details/49998511
 

 

上传文件的表单中<form>要加属性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","application/x-www-form- urlencoded"); 这两个要作的是同一件事情,就是设置表单传输的编码。在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

http://www.cnblogs.com/mumue/archive/2012/05/24/2515984.html


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

最近同事在作一个图片上传功能、在入参 body 中同时传入文件和其它基本信息结果出现如题异常、在此记录下解决办法、以作记录。

controller 代码以下:

复制代码
@RequestMapping(value = "/upload", method =RequestMethod.POST)
@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"

解决方案:

去掉 @RequestBody 注解就好了
缘由: 使用在进行图片或者文件上传时 multipart/form-data 类型时、 数据会自动进行映射不要添加任何注解。
加了@RequestBody后,因此参数都会转换成JSON,会影响 POST中上报数据流的格式
https://www.cnblogs.com/yueli/p/7552888.html

关键词:理解 http 消息头 
使用 multipart form-data 上传 文件
之前的章节已经介绍过了form传输表单的形式,可是在使用过程当中仍然有不少问题,这里再向你们详细介绍一下。

multipart/form-data是上传文件的一种方式。multipart/form-data其实就是浏览器用表单上传文件的方式。
最多见的情境是:在写邮件时,向邮件后添加附件,附件一般使用表单添加,也就是用multipart/form-data格式上传到服务器。

具体的步骤以下:

一、客户端和服务器创建连接(tcp协议)
二、客户端能够向服务器发送数据
三、客户端按照符合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=13068812771&format=js on&sign=6570c00315a94edac47414b6e9b681e0 http/1.0
content-type: multipart/form-data; boundary=------webkitformboundaryx3mhup4uhvo8zy3o
accept-charset: utf-8
host: gw.api.taobao.com
connection: close
content-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";


搜索此文相关文章:理解HTTP消息头 五——使用multipart/form-data上传文件
此文连接:http://www.makaidong.com/%E5%8D%9A%E5%AE%A2%E5%9B%AD%E6%90%9C/30170.shtml

 

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  
复制代码

解决办法:

关闭防火墙。https://blog.csdn.net/sunny_12138/article/details/79196107