【Javaweb】Ajax跨域问题及其解决方案
什么是Ajax
在Ajax没有出现的时候,大部分的网络资源获取都要经过这种过程:
1、浏览器发送请求
2、服务器接受请求,返回资源
3、浏览器得到资源,进行界面刷新(这个刷新是强制的)
但是这样就会出现一个问题,就是我不能局部刷新网页内容,如果要进行内容刷新就必须刷新整个界面。这样就很鸡肋了,比如说我想要给一篇文章点赞,点赞后需要刷新文章的总点赞数量,总不能把整个网页都给我刷新一遍吧,这样体验就太差了。
为了解决这个问题,Ajax出现了,Ajax不是一个语言,也不是一门新技术,它是一系列技术的结合,Ajax的全称为Asynchronous JavaScript + XML
。使用Ajax获取资源时,只是动态响应操作,发出对应的请求,得到返回结果或者资源,将其快速显示(或更新)到局部界面,这样就可以在得到资源的同时,不刷新整个界面。
为什么Ajax不能跨域
Ajax不能跨域,是因为浏览器都遵循了同源政策:不是“同协议、同域名、同端口” 的网页资源无法相互访问。Ajax就是采用了同源协议,所以Ajax无法访问非同源的资源。
但是from表单是可以跨域的,这是为什么呢?知乎上有个大佬说的很详细:
因为原页面用 form 提交到另一个域名之后,界面进行了刷新,原页面的脚本无法获取新页面中的内容,所以浏览器认为这是安全的。
而 AJAX 是可以读取响应内容的,因此浏览器不能允许你这样做。
如果你细心的话你会发现,其实请求已经发送出去了(Status Code: 200 OK ),你只是拿不到响应而已。所以浏览器这个策略的本质是,一个域名的 JS ,在未经允许的情况下,不得读取另一个域名的内容。但浏览器并不阻止你向另一个域名发送请求。
作者:方应杭
链接:https://www.zhihu.com/question/31592553/answer/190789780
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
如何解决Ajax跨域的问题?
目前普遍存在两种解决Ajax跨域问题的方法,一种是Jsonp(Json with padding),原理就是用<script>标签的src属性,动态加载js函数参数,因为src属性不受同源限制,同样img、iframe、link等标签都不受同源限制,但是Jsonp只能发送get请求;另一种是CORS(Cross Origin Resource Sharing),CORS的实现则需要在服务端的响应头中附加指定参数,让服务器端告诉浏览器,别让它禁止客户端和服务端之间的交流了。
CORS
CORS原理:服务器在收到请求之后,在响应参数中加入,Access-Control-Allow-Origin,Access-Control-Allow-Methods,Access-Control-Max-Age,Access-Control-Allow-Headers,Access-Control-Allow-Credentials等参数,浏览器在接收到返回值后会通过这些参数的设置来判断服务器是否支持跨域请求。所以我们在服务端增加一个过滤器,将所有进来的请求都加上响应参数。
下面以一个例子来说明CORS的使用方式:
CORS例子
目录组成
Test.java核心部分
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setCharacterEncoding("utf-8");
response.getWriter().write("{\"name\":\"xxxxxxxx\"}");
}
SimpleCORSFilter.java核心部分
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
//设置所有的请求都可以实现Ajax跨域
httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
//支持http的POST,GET,OPTIONS,DELETE四种请求方式
httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
httpServletResponse.setHeader("Access-Control-Max-Age", "60");
httpServletResponse.setHeader("Access-Control-Allow-Headers", "x-requested-with");
//是否支持cookie跨域
//httpServletResponse.addHeader("Access-Control-Allow-Credentials", "true");
chain.doFilter(request, response);
}
/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException {
// TODO Auto-generated method stub
}
需要注意一点:Access-Control-Allow-Credentials用于标记是否支持cookie跨域,但是设置为true的情况下,Access-Control-Allow-Origin不能设置为*
,这是因为请求的首部中携带了 Cookie 信息,如果 Access-Control-Allow-Origin 的值为*
,请求将会失败。在指定域名的情况下的可以设置Access-Control-Allow-Credentials为true,从而可以接受指定域名请求的Cookie。
写完过滤器之后,需要在web.xml中进行过滤器的配置,具体配置内容如下:
web.xml核心部分
<filter>
<filter-name>Simple CORSFilter</filter-name>
<filter-class>filter.SimpleCORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Simple CORSFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Ajax test</title>
<!-- 引入jQuery -->
<script src="./js/jquery.min.js"></script>
<script type="text/javascript">
$.ajax({
//从本地localhost的8080端口向www.xxxx.com域名的8080端口发送ajax请求
url:"http://www.xxxx.com:8080/Ajax_Cross_Origin/Test",
type: "get",
dataType:"json",
xhrFields: {
//设置要不要携带Cookie信息,true为携带,fasle为不携带
withCredentials: false
},
crossDomain: true,
success:function (data) {
alert("12345");
console.log(data);
}
});
</script>
</head>
<body>
<h1>测试ajax跨域</h1>
</body>
</html>
我将项目部署在服务器的tomcat容器里,域名为www.xxxx.com,然后在本机的tomcat中也部署了这个项目,输入http://localhost:8080/Ajax_Cross_Origin/index.html
,在Network中可以看到如下信息:
在Console中看到如下信息:
Ajax跨域请求成功。
Jsonp
在实际工作中,CORS的使用频率比Jsonp要高很多,所以这里不细讲Jsonp的具体实现方式了。需要注意的一点是,Jsonp虽然是解决Ajax跨域问题提出来的技术,但是它和Ajax半毛钱关系都没有,因为Jsonp的实现是通过<script>的src属性实现的,Ajax是通过XMLHttpRequest实现的。对于想进一步了解Jsonp的小伙伴,强列推荐你们看这篇文章:
Jsonp解决ajax跨域问题
写的非常棒!