ssm整合 ,ajax json请求406
'# SSM整合,AJAX JSON请求406错误的深度解析与实战指南
一、背景与问题
在SSM(Spring + Spring MVC + MyBatis)整合开发中,AJAX请求返回JSON数据时,常出现406 Not Acceptable错误。这种错误通常与HTTP协议的MIME类型协商机制有关。Spring MVC框架在处理请求时,会根据客户端请求头中的Accept字段判断是否支持指定的MIME类型(如application/json)。若服务器端未正确配置或未处理相应请求,就会返回406错误。
在实际开发中,常见的场景包括:前端通过AJAX请求后端接口获取数据时,后端未正确返回JSON格式,或未设置Content-Type头为application/json,导致客户端无法正确解析响应数据。
二、基本原理
Spring MVC处理AJAX请求的核心流程如下:
- 请求拦截:通过
HandlerMapping匹配请求路径和控制器方法 - 参数绑定:通过
HandlerAdapter解析请求参数 - 返回值处理:根据返回值类型决定响应格式(如
ModelAndView、String、@ResponseBody等) - MIME类型协商:根据
Accept头选择合适的响应格式 - 响应发送:通过
HttpServletResponse返回响应数据
当使用@ResponseBody注解时,Spring会通过HttpMessageConverter将返回值转换为JSON格式。若未配置相关转换器(如Jackson库),或未正确设置Content-Type头,就会导致406错误。
三、环境准备
开发环境要求:
- JDK 1.8+
- Maven 3.x
- Spring 5.x
- Jackson 2.x
- MySQL 8.x(可选)
项目结构建议:
src
├── main
│ ├── java
│ │ └── com.example.ssm
│ │ ├── controller
│ │ ├── service
│ │ └── dao
│ └── resources
│ ├── application.properties
│ └── springmvc-servlet.xml
└── test四、核心实现
1. 基础配置(错误示例)
// 错误配置:未配置Jackson支持
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
// 未配置消息转换器
}错误原因:Spring默认不包含Jackson库,导致无法处理JSON格式的返回值。
2. 正确配置(推荐方案)
// 正确配置:启用Jackson支持
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
@Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
return new Jackson2ObjectMapperBuilder()
.failOnUnknownProperties(false)
.enable(FAIL_ON_EMPTY_BEAN)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
}
}关键点:通过Jackson2ObjectMapperBuilder配置Jackson的格式化规则,确保JSON转换时的兼容性。
3. 控制器方法实现
@RestController
@RequestMapping("/api")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users")
public ResponseEntity<List<User>> getUsers() {
List<User> users = userService.findAll();
return ResponseEntity.ok(users);
}
}关键点:
- 使用
@RestController注解替代@Controller+@ResponseBody ResponseEntity提供更灵活的响应控制@GetMapping明确指定HTTP方法
五、完整案例
1. 项目结构
src
├── main
│ ├── java
│ │ └── com.example.ssm
│ │ └── controller
│ │ └── UserController.java
│ │ └── model
│ │ └── User.java
│ │ └── service
│ │ └── UserService.java
│ │ └── dao
│ │ └── UserDao.java
│ └── resources
│ └── application.properties2. 配置文件
<!-- springmvc-servlet.xml -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd">
<context:component-scan base-package="com.example.ssm"/>
<mvc:annotation-driven />
<mvc:default-servlet-handler />
</beans>3. 数据模型
// User.java
public class User {
private Long id;
private String name;
private String email;
// getters and setters
}4. 前端调用示例
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>AJAX JSON Test</title>
</head>
<body>
<button onclick="fetchUsers()">获取用户数据</button>
<div id="result"></div>
<script>
function fetchUsers() {
fetch('/api/users', {
method: 'GET',
headers: {
'Accept': 'application/json'
}
})
.then(response => {
if (!response.ok) throw new Error('Network response was not ok');
return response.json();
})
.then(data => {
const resultDiv = document.getElementById('result');
resultDiv.textContent = JSON.stringify(data, null, 2);
})
.catch(error => {
console.error('Error:', error);
});
}
</script>
</body>
</html>5. 控制器实现
// UserController.java
@RestController
@RequestMapping("/api")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users")
public ResponseEntity<List<User>> getUsers() {
List<User> users = userService.findAll();
return ResponseEntity.ok(users);
}
}六、源码解析
Spring MVC处理JSON请求的核心流程如下:
- 请求拦截:通过
HandlerMapping匹配路径,调用HandlerAdapter - 参数绑定:
HandlerAdapter解析请求参数,调用HandlerMethodArgumentResolver - 返回值处理:根据
@ResponseBody注解,使用HttpMessageConverter转换返回值 - MIME类型协商:通过
ContentNegotiationManager选择合适的转换器 - 响应发送:设置
Content-Type头为application/json,写入响应体
关键代码片段(Jackson配置):
@Bean
public Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder() {
return new Jackson2ObjectMapperBuilder()
.failOnUnknownProperties(false)
.enable(FAIL_ON_EMPTY_BEAN)
.dateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
}七、进阶使用
1. 复杂数据转换
@GetMapping("/users")
public ResponseEntity<List<User>> getUsers() {
List<User> users = userService.findAll();
return ResponseEntity.ok(users);
}2. POST请求处理
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {
User createdUser = userService.save(user);
return ResponseEntity.status(HttpStatus.CREATED).body(createdUser);
}3. 异常处理
@ExceptionHandler
public ResponseEntity<String> handleException(Exception ex) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(ex.getMessage());
}八、性能与工程实践
1. 性能优化
- 缓存机制:对频繁访问的接口添加缓存
- 异步处理:对耗时操作使用
@Async注解 - GZIP压缩:配置
Content-Encoding头为gzip - 连接池配置:调整
HttpClient的连接池参数
2. 安全风险
- CSRF防护:对于POST请求需添加
@EnableWebSecurity配置 - 数据验证:使用
@Valid注解进行参数校验 - SQL注入:MyBatis中使用
#{}参数绑定避免注入
九、常见问题与踩坑
1. 常见错误
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 406错误 | 未配置Jackson库 | 添加Jackson依赖 |
| 400错误 | 参数绑定失败 | 检查@RequestBody字段类型 |
| 500错误 | 异常未处理 | 添加@ExceptionHandler |
| 415错误 | 未设置Content-Type | 在前端设置headers |
2. 高级问题
- 跨域问题:配置
@CrossOrigin注解或使用CORS过滤器 - 版本控制:通过
@RequestMapping的params属性区分版本 - 日志监控:在
application.properties中配置logging.level级别
十、最佳实践
- 统一返回结构:定义
Result类封装返回数据 - 接口版本控制:通过
/api/v1/路径区分接口版本 - 分页处理:对大数据量接口使用分页机制
- 缓存策略:对静态数据接口添加缓存
- 异常处理:统一异常处理机制,避免暴露敏感信息
十一、总结
SSM整合中AJAX JSON请求406错误的根源在于HTTP MIME类型协商机制和Spring MVC的返回值处理机制。通过正确配置Jackson库、合理使用@RestController注解、配置Content-Type头等措施,可以有效解决该问题。在实际开发中,建议优先使用@RestController替代传统@Controller+@ResponseBody组合,同时注意处理跨域、异常、安全等潜在问题。对于高性能要求的场景,可考虑引入缓存、异步处理等优化手段。通过深入理解Spring MVC的处理流程,开发者可以更灵活地应对各种复杂的业务需求。
评论已关闭