AJAX解决跨域(包括json)
1 分析AJAX的contentType
ajax的contentType指的是传递data到后端所使用的内容格式,我们这里主要说两种
x-www-form-urlencoded
这是ajax默认的数据传输格式,是在请求体当中通过键值对的格式进行传输的,如下
name=1&age=12
这种方法有一个缺憾,就是当传复杂嵌套数据对象的时候,无法正确解析,比如
data:{
name:"zong",
age:"12",
teacher: {
name :"wang",
age:"25"
}
}
代码使用如下
$.ajax({
url:"http://localhost:8081/blog/t",
type:"post",
data: {
"tagId":"1",
"tagName":"2",
"total":"1",
),
success:function(obj){
alert(123)
},
})
后端接收
@RequestMapping("/test")
public Map<String,Object> test(BlogTag blogTag){
Map<String,Object> datas = new HashMap<>();
System.out.println(blogTag);
return datas;
}
json
这是一种流行的数据传输格式,通过json字符串的格式传输数据,支持嵌套
代码使用如下
$.ajax({
url:"http://localhost:8081/blog/t",
type:"post",
data: JSON.stringify({
"tagId":"1",
"tagName":"2",
"total":"1",
}), // 序列化json字符串
contentType: "application/json", //指定请求头
dataType:'json',
success:function(obj){
alert(123)
},
})
后端接收
@RequestMapping("/test") // 如果设置为ResponseBody就对前端的contentType有要求,会自动反序列化
public Map<String,Object> test(@RequestBody BlogTag blogTag){
Map<String,Object> datas = new HashMap<>();
System.out.println(blogTag );
return datas;
}
2 跨域问题出现
CORS,跨域问题
我们着重看后面的内容,需要打开服务器对客户端的Access-Control-Allow-Origin
我们编写一个过滤器
package com.zong.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(urlPatterns = "/*", filterName = "CORSFilter")
public class CORSFilter implements Filter {
/**
* 此过滤器只是处理跨域问题
* @param servletRequest
* @param servletResponse
* @param chain
* @throws ServletException
* @throws IOException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
String origin = req.getHeader("Origin");
if(origin == null) {
origin = req.getHeader("Referer");
}
resp.setHeader("Access-Control-Allow-Origin", origin); // 解决跨域的核心代码,放行的客户端
// resp.setHeader("Access-Control-Allow-Credentials", "true");
//true代表允许携带cookie,这行代码需要前端传输的时候添加请求头withCredentials = true 两个都设置true 才起效
chain.doFilter(servletRequest,servletResponse);
}
}
这样,x-www-form-unlencoded可以正常通信,但是json格式的数据还是报跨域问题
为什么
我们先了解一下两种格式在传输时的不同
预检 (preflight request )
当contentType为json的时候,ajax会先发送一个preflight request 到后端,如图
这个预检,会对要传输数据的一些信息放入请求头
服务端需要对这些请求头,做出响应,如果不响应就会出现如图这种跨域问题
注意这个in preflight response
解决问题
现在我们出现一个问题就解决一个问题呗,需要响应头,我们就给他响应头
上图转载自:Access-Control-Allow-Headers是什么?有什么作用?
package com.zong.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(urlPatterns = "/*", filterName = "CORSFilter")
public class CORSFilter implements Filter {
/**
* 此过滤器只是处理跨域问题
* @param servletRequest
* @param servletResponse
* @param chain
* @throws ServletException
* @throws IOException
*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
String origin = req.getHeader("Origin");
if(origin == null) {
origin = req.getHeader("Referer");
}
resp.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
resp.setHeader("Access-Control-Allow-Headers", "Content-Type,XFILENAME,XFILECATEGORY,XFILESIZE,x-requested-with,Authorization"); // 设置Content-Type,如上面说的那三种由于不需要预检,所以这里的Content-Type指的是json
resp.setHeader("Access-Control-Allow-Origin", origin);//这里不能写*,*代表接受所有域名访问,如写*则下面一行代码无效。谨记
resp.setHeader("Access-Control-Allow-Credentials", "true");//true代表允许携带cookie
chain.doFilter(servletRequest,servletResponse);
}
}
如此问题全部解决