在 Spring Boot 中,如果你遇到 Content-Type 'application/x-www-form-urlencoded;charset=UTF-8' is not supported
错误,通常是因为 Controller 方法没有正确接收 application/x-www-form-urlencoded
格式的请求。
1. 问题原因
application/x-www-form-urlencoded
是一种常见的 HTTP 请求格式,通常用于 表单提交 或 API 请求(如微信支付回调、OAuth2 授权等)。
Spring Boot 默认支持这种格式,但需要:
- Controller 方法参数正确绑定(如
@RequestParam
或MultiValueMap
)。 - 请求体没有被
@RequestBody
解析(@RequestBody
仅适用于JSON
/XML
等格式)。
2. 解决方案
方案 1:使用 @RequestParam
接收单个参数
如果请求是 key=value&key2=value2
格式,可以直接用 @RequestParam
接收:
@PostMapping("/submit")
public String handleFormSubmission(
@RequestParam("key1") String value1,
@RequestParam("key2") String value2
) {
System.out.println("key1=" + value1 + ", key2=" + value2);
return "success";
}
适用场景:
- 请求参数较少,且固定。
方案 2:使用 MultiValueMap
接收所有参数
如果请求参数较多,或者不确定参数名,可以用 MultiValueMap
接收:
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FormController {
@PostMapping(value = "/submit", consumes = "application/x-www-form-urlencoded")
public String handleFormSubmission(MultiValueMap<String, String> formData) {
formData.forEach((key, values) -> {
System.out.println(key + "=" + String.join(",", values));
});
return "success";
}
}
注意:
-
@RequestBody
不能直接用于application/x-www-form-urlencoded
,必须加consumes = "application/x-www-form-urlencoded"
。 -
MultiValueMap
适用于POST
请求,GET
请求参数可以直接用@RequestParam
。
方案 3:使用 @ModelAttribute
绑定到对象
如果请求参数可以映射到一个 Java 对象,可以用 @ModelAttribute
:
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class FormController {
@PostMapping(value = "/submit", consumes = "application/x-www-form-urlencoded")
public String handleFormSubmission(@ModelAttribute FormData formData) {
System.out.println("name=" + formData.getName() + ", age=" + formData.getAge());
return "success";
}
public static class FormData {
private String name;
private int age;
// 必须有无参构造方法
public FormData() {}
// Getter 和 Setter(Spring 会自动调用)
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
}
适用场景:
- 请求参数较多,且可以映射到 Java 对象。
方案 4:检查 Content-Type
是否正确
如果前端发送的 Content-Type
不是 application/x-www-form-urlencoded
,Spring Boot 可能无法正确解析。
确保前端代码正确设置 Content-Type
:
前端(JavaScript)示例
fetch("/submit", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
},
body: new URLSearchParams({
key1: "value1",
key2: "value2"
}).toString() // 自动编码为 key1=value1&key2=value2
});
注意:
-
URLSearchParams
会自动编码key=value
格式。 - 不要手动拼接
key=value&key2=value2
,否则可能因特殊字符(如&
、=
)导致解析错误。
方案 5:检查是否被 @RequestBody
拦截
如果 Controller 方法使用了 @RequestBody
,Spring Boot 会尝试解析 JSON
/XML
,而不是 application/x-www-form-urlencoded
。
错误示例:
@PostMapping("/submit")
public String handleFormSubmission(@RequestBody Map<String, String> formData) {
// ❌ 错误!@RequestBody 不能用于 application/x-www-form-urlencoded
return "success";
}
正确做法:
- 去掉
@RequestBody
,改用@RequestParam
或MultiValueMap
。
3. 完整示例
Controller
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;
@RestController
public class FormController {
// 方式1:@RequestParam 接收单个参数
@PostMapping("/submit1")
public String handleForm1(
@RequestParam("name") String name,
@RequestParam("age") int age
) {
return "name=" + name + ", age=" + age;
}
// 方式2:MultiValueMap 接收所有参数
@PostMapping(value = "/submit2", consumes = "application/x-www-form-urlencoded")
public String handleForm2(MultiValueMap<String, String> formData) {
return formData.toString();
}
// 方式3:@ModelAttribute 绑定到对象
@PostMapping(value = "/submit3", consumes = "application/x-www-form-urlencoded")
public String handleForm3(@ModelAttribute FormData formData) {
return formData.toString();
}
public static class FormData {
private String name;
private int age;
// Getter & Setter
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
@Override
public String toString() {
return "FormData{name='" + name + "', age=" + age + "}";
}
}
}
前端请求示例
// 方式1:手动拼接 URLSearchParams
fetch("/submit1", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
},
body: new URLSearchParams({
name: "Alice",
age: "25"
}).toString()
});
// 方式2:直接发送 key=value&key2=value2
fetch("/submit2", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
},
body: "name=Bob&age=30"
});
4. 常见问题排查
问题 | 解决方案 |
---|---|
Content-Type 不是 application/x-www-form-urlencoded | 检查前端是否正确设置 headers |
@RequestBody 导致解析失败 | 去掉 @RequestBody ,改用 @RequestParam 或 MultiValueMap |
参数无法绑定到对象 | 确保对象有 Getter/Setter ,并且字段名匹配 |
特殊字符(如 + 、& )解析错误 | 使用 URLSearchParams 自动编码 |
总结
-
application/x-www-form-urlencoded
适用于表单提交,不能直接用@RequestBody
。 - 推荐方式:
- 少量参数 →
@RequestParam
- 多个参数 →
MultiValueMap
- 对象映射 →
@ModelAttribute
- 少量参数 →
- 前端必须正确设置
Content-Type
,并确保数据格式正确(如key=value&key2=value2
)。
如果你的问题仍未解决,请提供 Controller 代码 和 前端请求示例,我可以进一步帮你排查! 🚀