No 'Access-Control-Allow-Origin' header is present on the requested resource.
前言
- ajax跨域问题,主要原因是因为浏览器的“同源策略”
- 若是iframe属于另外的范畴,可以使用 document.domain
- 若是改不了后台代码建议使用nginx,请求都通过nginx转发
先上解决方案
- 将非简单请求改为简单请求 注释掉Content-Type(Content-Type字段的类型为application/json时为非简单请求。)
- 然后在Servlet中的response 添加头信息 Access-Control-Allow-Origin
- 如:
response.setHeader("Access-Control-Allow-Origin", "*");
修改前状态 - 现象如下
修改完成后 - 现象如下
跨域的简要描述
在A网站中,我们希望使用Ajax来获得B网站中的特定内容。如果A网站与B网站不在同一个域中,那么就出现了跨域访问问题。你可以理解为两个域名之间不能跨过域名来发送请求或者请求数据,否则就是不安全的。跨域访问违反了同源策略,
同源策略规定,浏览器的ajax只能访问跟它的HTML页面同源(相同域名或IP)的资源。
补充:127.0.0.1 访问 本地的IP也算跨域 (可方便测试)
- 现在所有支持JavaScript的浏览器都会使用这个策略
- 协议、域名、端口号都相同,只要有一个不相同,那么都是非同源。
- 同源策略限制的情况:
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM 和 Js对象无法获得
- AJAX 请求不能发送
- 注意:对于像 img、iframe、script 等标签的src属性是特例,它们是可以访问非同源网站的资源的。
CORS实现原理
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
基本上目前所有的浏览器都实现了CORS标准,其实目前几乎所有的浏览器ajax请求都是基于CORS机制的,只不过可能平时前端开发人员并不关心而已(所以说其实现在CORS解决方案主要是考虑后台该如何实现的问题)。
只要同时满足以下两大条件,就属于简单请求。
(1) 请求方法是以下三种方法之一:
- HEAD
- GET
- POST
(2)HTTP的头信息不超出以下几种字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
Java解决方案
无论是使用webservice还是servlet请求都需要通过doPost或者doOptions方法
若是你是HTTP请求
@Override
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
resp.setHeader("Access-Control-Allow-Credentials", "true");
if (req.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(req.getMethod())) {
resp.addHeader("Access-Control-Allow-Methods", "POST,GET,TRACE,OPTIONS,DELETE");
resp.addHeader("Access-Control-Allow-Headers", "Content-Type,Origin,Accept");
resp.addHeader("Access-Control-Max-Age", "1800");
}
super.doOptions(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
resp.setHeader("Access-Control-Allow-Credentials", "true");
if (req.getHeader("Access-Control-Request-Method") != null && "OPTIONS".equals(req.getMethod())) {
resp.addHeader("Access-Control-Allow-Methods", "POST,GET,TRACE,OPTIONS,DELETE");
resp.addHeader("Access-Control-Allow-Headers", "Content-Type,Origin,Accept");
resp.addHeader("Access-Control-Max-Age", "1800");
}
// ....
}
若是是webservice请求,我这里使用的是Axis2,只需要在头中多加一个SOAPAction
Servlet需要使用自己的直接继承AxisServlet,然后重写doPost和doOptionsresp.addHeader("Access-Control-Allow-Headers", "Content-Type,Origin,Accept,SOAPAction");
最后
这次总算是摸透了
资料参考
ajax跨域,这应该是最全的解决方案了