记录一次奇怪的前后端交互问题(Ajax请求浏览器响应406错误)

今天在做ssm项目的时候,写了一个ssm整合测试,web.xml配置如下

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
  	<!-- needed for ContextLoaderListener -->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:spring-persist-*.xml</param-value>
	</context-param>

	<!-- Bootstraps the root web application context before servlet initialization -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	
	<filter>
		<filter-name>CharacterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceRequestEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <param-name>forceResponseEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
	</filter>
	
	<filter-mapping>
		<filter-name>CharacterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
	
	<!-- The front controller of this Spring Web application, responsible for handling all application requests -->
	<servlet>
		<servlet-name>springDispatcherServlet</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>classpath:spring-web-mvc.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<!-- Map all requests to the DispatcherServlet for handling -->
	<servlet-mapping>
		<servlet-name>springDispatcherServlet</servlet-name>
		<url-pattern>*.html</url-pattern>
		<url-pattern>*.json</url-pattern>
	</servlet-mapping>
</web-app>

前端index.jsp的代码如下

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<base href="http://${pageContext.request.serverName}:${pageContext.request.serverPort}${pageContext.request.contextPath}/">
<script type="text/javascript" src="jquery/jquery-2.1.1.min.js"></script>
<script type="text/javascript">
	$(function(){

		$("#btn4").click(function(){
			var student={
					"stuId":5,
					"stuName":"孙培养",
					"address":{
						"province":"河南",
						"city":"南阳",
						"street":"淅川县金河镇"
					},
					"subjectList":[
						{
							"subjectName":"Java",
							"subjectScore":"100"
						},{
							"subjectName":"Android",
							"subjectScore":"90"
						}
					],
					"map":{
						"k1":"v1",
						"k2":"v2",	
					}
			};
			var requestBody=JSON.stringify(student);
			$.ajax({
				"url":"send/compose/object.html",
				"type":"post",			
				"data":requestBody,
				"contentType":"application/json;charset=UTF=8",
				"dataType":"json",
				"success":function(response){
					console.log(response);
				},
				"error":function(response){
					console.log(response);
				}
			});
		});
		
	});
</script>
</head>
<body>
	<br><br>
	<button id="btn4">send student</button>
</body>
</html>

后端controller层的代码如下

import java.util.List;

import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import com.atguigu.crowd.entity.Admin;
import com.atguigu.crowd.entity.ParamData;
import com.atguigu.crowd.entity.Student;
import com.atguigu.crowd.service.api.AdminService;
import com.atguigu.crowd.util.ResultEntity;

@Controller
public class TestHandler {

	private static Logger logger=LoggerFactory.getLogger(TestHandler.class);
	
	@ResponseBody
	@RequestMapping(value="/send/compose/object.html")
	public ResultEntity<Student> receiveComposeObject(@RequestBody Student student){
		logger.info(student.toString());
		return ResultEntity.successWithData(student);
	}
	
}

启动Tomcat之后,访问index.jsp

在这里插入图片描述

点击按钮之后,发现结果出人意料

在这里插入图片描述
下面是ajax请求返回的响应

在这里插入图片描述
406错误出现的原因大多是因为前端设置接收的数据类型与后端返回的数据类型不匹配导致的,但是怪就怪在我的ajax请求设置的dataType为json格式,而后端同样是通过@ResponseBody注解返回了json格式,前后端的格式很显然是相互匹配的,那么又为什么会造成406错误呢?

根据下面这张图可以看出前端请求头中的数据格式均为json,而后台响应的“Content-Type”为“text/html;charset=utf-8”,所以很可能就是后台没有成功返回json格式数据造成的。
在这里插入图片描述
于是我首先想到了给responsebody对象设置content-type

resp.setContentType("application/json;charset=UTF-8");

然而运行之后406报错依旧,百度了一下,几乎所有的经验都是告诉我使用response没用,需要设置一下后端RequestMapping注解中的produces(为了以防万一,我并没有去掉resp.setContentType)

@ResponseBody
	@RequestMapping(value="/send/compose/object.html",produces= "application/json;charset=UTF-8")
	public ResultEntity<Student> receiveComposeObject(@RequestBody Student student,HttpServletResponse resp){
		resp.setContentType("application/json;charset=UTF-8");
		logger.info(student.toString());
		return ResultEntity.successWithData(student);
	}

本以为就这样大功告成了,结果运行之后还是406错误!!!看了下响应头信息,发现“Content-Type”依然为“text/html;charset=utf-8”,整个人就很懵逼了,看来不能根据以往的经验来确定前后端交互的效果了。想了一下,觉得还是因为响应Content-Type的原因,既然返回一直固定为html格式,那么肯定跟请求路径的后缀多少有些关系,难道是因为后缀是html?于是我试着把ajax请求地址和controller映射地址的后缀都改成了json

在这里插入图片描述
在这里插入图片描述
重新启动项目,点击按钮,响应成功!响应信息的“Content-Type”变成了“application/json;charset=UTF-8”,也间接证明了之前的猜想是正确的

在这里插入图片描述

再看后台日志,成功打印出前端请求数据

在这里插入图片描述
虽然问题算是就此解决了,也知道了是由于请求路径后缀造成这次的问题,但更深入的原因,查了很多资料后还是不清楚,可能跟浏览器的底层有关系吧。但是到此还没有完,既然知道了跟后缀有关,或许可以改一下web.xml配置的后缀来更优雅的解决该问题,而不是每次ajax请求后都要用json做后缀。我这里在web.xml中将spring的分发拦截映射的后缀改为"*.do"

在这里插入图片描述

接着将前后台代码的路径也改过来

在这里插入图片描述

在这里插入图片描述
重启项目,点击按钮

在这里插入图片描述

大功告成,打完收工!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值