Spring Boot接收请求时出现 Content type ‘application/x-www-form-urlencoded;charset=UTF-8‘ not supported

问题原因

今天在调试一个发送短信的HTTP接口时候,在SpringBoot接口的接收请求时出现 Content type ‘application/x-www-form-urlencoded;charset=UTF-8’ not supported;由报错日志可知使用@RequestBody注解解析,那么对应支持发送数据的请求头数据格式应该是application/json
在这里插入图片描述

再回去看发送方发送数据请求头设置的数据格式为application/x-www-form-urlencoded,然后导致接收方接口中使用了(@RequestBody TokenBean tokenBean)方式来解析HTTP请求体body中的json对象导致出错,将Content-Type方式修改为application/json就可以正常解析了。
在这里插入图片描述

那为什么@RequestBody不支持数据格式为application/x-www-form-urlencoded的呢?这就要知道@RequestBody的作用是什么?以及我们知道另外一个注解@RequestParam有何它有什么关系呢?

@RequestBody和@RequestParam

@RequestBody主要用来接收前端传递给后端的json字符串中的数据的(请求体中的数据的)

GET方式无请求体,所以使用@RequestBody接收数据时,前端不能使用GET方式提交数据,而是用POST方式进行提交。

在后端的同一个接收方法里,@RequestBody与@RequestParam()可以同时使用,@RequestBody最多只能有一个,而@RequestParam()可以有多个。即一个请求只有一个@RequestBody;一个请求可以有多个@RequestParam。

注解@RequestParam接收的参数是来自requestHeader中,即请求头。
RequestParam可以接受简单类型的属性,也可以接受对象类型。
@RequestParam有三个配置参数:
required 表示是否必须,默认为 true,必须。
defaultValue 可设置请求参数的默认值。
value 为接收url的参数名(相当于key值)。
@RequestParam用来处理 Content-Type 为 application/x-www-form-urlencoded 编码的内容,Content-Type默认为该属性。@RequestParam也可用于其它类型的请求,例如:POST、DELETE等请求。

@RequestParam 底层是通过request.getParameter方式获得参数的,也就是说,@RequestParam 和request.getParameter是同一回事。因为使用request.getParameter()方式获取参数,可以处理get 方式中queryString的值,也可以处理post方式中 body data的值。如果请求传的是Json对象则后端可以使用@RequestParam。

所以在postman中,要选择body的类型为 x-www-form-urlencoded,这样在headers中就自动变为了 Content-Type : application/x-www-form-urlencoded 编码格式。

参考文章如下:https://blog.csdn.net/weixin_38004638/article/details/99655322

Content-type的类型

这里需要说明一下HTTP的POST请求的数据格式,在HTTP的请求头中,可以使用Content-type来指定不同格式的请求信息。

常见的媒体格式类型:

text/html : HTML格式
text/plain :纯文本格式      
text/xml :  XML格式
image/gif :gif图片格式    
image/jpeg :jpg图片格式 
image/png:png图片格式

以applicaton开头的类型:

application/json    : JSON数据格式
application/xhtml+xml :XHTML格式
application/xml     : XML数据格式
application/atom+xml  :Atom XML聚合格式    
application/pdf       :pdf格式  
application/javascript :js格式
application/msword  : Word文档格式
application/octet-stream : 二进制流数据(如常见的文件下载)
application/x-www-form-urlencoded :form表单默认的数据格式类型,form表单数据被编码为key/value格式发送到服务器。
multipart/form-data : 需要在表单中进行文件上传时,就需要使用该格式。

除了原生的content-type,开发人员也可以完全自定义数据提交格式!

最常用的三种:

(1)application/x-www-form-urlencoded,form表单默认的数据格式,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。大部分服务端语言都对这种方式有很好的支持。

# Request Header
POST /adduser HTTP/1.1
Host: localhost:8030
Connection: keep-alive
Content-Length: 16
Pragma: no-cache
Cache-Control: no-cache
Origin: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9

# Form Data
name=name&age=11

(2)application/json,现在越来越多的人把它作为请求头,用来告诉服务端消息主体是序列化后的 JSON 字符串。服务端语言也有很多函数去解析JSON,使用JSON可以支持更加复杂的结构化数据。

# Request Header
POST /adduser HTTP/1.1
Host: localhost:8030
Connection: keep-alive
Content-Length: 24
Pragma: no-cache
Cache-Control: no-cache
Origin: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Content-Type: application/json
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9

# Request Payload
{"name":"121","age":121}

(3)multipart/form-data,对用于在表单中上传文件时,也可以上传普通数据,只需要让from的ectyle等于multipart/form-data就可以了。比如下面的http请求格式:

# Request Header
POST /adduser HTTP/1.1
Host: localhost:8030
Connection: keep-alive
Content-Length: 232
Pragma: no-cache
Cache-Control: no-cache
Origin: chrome-extension://fdmmgilgnpjigdojojpjoooidkmcomcm
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryBRi81vNtMyBL97Rb
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9

# Request Payload

------WebKitFormBoundaryBRi81vNtMyBL97Rb
Content-Disposition: form-data; name="name"
name1
------WebKitFormBoundaryBRi81vNtMyBL97Rb
Content-Disposition: form-data; name="age"
12
------WebKitFormBoundaryBRi81vNtMyBL97Rb--

这种格式的数据会有一个边界线boundary(这里就是------WebKitFormBoundaryBRi81vNtMyBL97Rb)用于分割不同的字段,为了避免与正文内容重复,boundary很长很复杂。消息主体以boundary开始,紧接着就是内容描述信息,然后是回车,最后是字段具体的内容(文本或二进制)。如果传输的是文件,还要包含文件名和文件类型信息。消息主体以boundary结束。

### 解决方案 当遇到 `Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported` 的错误,通常是因为控制器方法未正确配置以处理该类型的请求。以下是可能的原因以及解决方案: #### 原因分析 1. **缺少正确的注解** 如果使用的是表单数据提交方式 (`application/x-www-form-urlencoded`),则需要在控制器的方法参数上添加 `@RequestParam` 或者 `@ModelAttribute` 注解来绑定请求中的键值对[^1]。 2. **不匹配的 Content-Type 配置** 默认情况下,Spring Boot 控制器可能会期望 JSON 数据而不是 URL 编码的数据。如果希望支持 `application/x-www-form-urlencoded` 类型,则需显式声明支持此类型的内容解析。 3. **HttpMessageConverter 问题** Spring 使用 HttpMessageConverters 来转换 HTTP 请求体和响应体。默认情况下,某些 Converters 可能未启用或者未正确定义,从而导致无法识别特定的 Content-Type[^3]。 --- #### 实现步骤说明 ##### 方法一:修改 Controller 参数定义 对于基于 `application/x-www-form-urlencoded` 的 POST 请求,在接收参数的地方应采用如下形式: ```java @PostMapping(consumes = "application/x-www-form-urlencoded") public ResponseEntity<String> handleFormSubmission( @RequestParam String hiveTableName, @RequestParam String tableImportType, @RequestParam String pkColumn, @RequestParam String incrementColumn, @RequestParam String cron, @RequestParam Integer datasetId) { // 处理逻辑... return ResponseEntity.ok("Success"); } ``` 上述代码通过 `@RequestParam` 显式指定了每个字段名称及其对应的变量名,确保能够正确映射来自客户端发送的键值对。 ##### 方法二:利用 DTO 对象封装参数 另一种更简洁的方式是创建一个 Data Transfer Object (DTO),并将所有参数集中到一起: ```java public class ImportRequestDto { private String hiveTableName; private String tableImportType; private String pkColumn; private String incrementColumn; private String cron; private int datasetId; // Getters 和 Setters ... } @PostMapping(value = "/import", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE) public ResponseEntity<String> importData(@ModelAttribute ImportRequestDto dto) { System.out.println(dto.getHiveTableName()); // 进一步业务操作... return ResponseEntity.status(HttpStatus.CREATED).body("Resource created successfully."); } ``` 这里的关键在于使用了 `@ModelAttribute` 而不是 `@RequestBody`,因为后者主要用于解析 JSON 格式的请求体。 ##### 方法三:调整全局消息转换器设置 如果项目中有多个地方需要用到这种格式的支持,可以考虑自定义 Message Converter 并注册它到 Spring 容器中去: ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void configureMessageConverters(List<HttpMessageConverter<?>> converters) { FormEncodingHttpMessageConverter converter = new FormEncodingHttpMessageConverter(); converter.setReadHiddenHttpMethodField(false); Charset charset = StandardCharsets.UTF_8; List<MediaType> mediaTypes = Arrays.asList(new MediaType("application","x-www-form-urlencoded",charset)); converter.setSupportedMediaTypes(mediaTypes); converters.add(0,converter); // 添加至首位优先级最高 } } ``` 这样做的好处是可以统一管理所有的 form 表单编码需求而无需逐个更改 controller 层实现细节[^4]。 --- ### 注意事项 - 当上传文件,请注意区分普通的 key-value pairs 和 binary 文件流之间的差异。例如上面提到的例子中,“myFile”代表的就是实际待传输文档的位置信息[^2]。 - 确认服务器端日志级别已设为至少 info ,以便观察随机密码打印情况以及其他潜在异常提示。 ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序员小台

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值