No 'Access-Control-Allow-Origin' header is present on the requested resource.

前言

  • ajax跨域问题,主要原因是因为浏览器的“同源策略”
  • 若是iframe属于另外的范畴,可以使用 document.domain
  • 若是改不了后台代码建议使用nginx,请求都通过nginx转发

先上解决方案

  1. 将非简单请求改为简单请求 注释掉Content-Type(Content-Type字段的类型为application/json时为非简单请求。)
  2. 然后在Servlet中的response 添加头信息 Access-Control-Allow-Origin
  • 如: response.setHeader("Access-Control-Allow-Origin", "*");

修改前状态 - 现象如下

jQuery的ajax设置跨域请求头_解决方案


jQuery的ajax设置跨域请求头_jQuery的ajax设置跨域请求头_02


jQuery的ajax设置跨域请求头_解决方案_03

修改完成后 - 现象如下

jQuery的ajax设置跨域请求头_同源策略_04

跨域的简要描述

在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和doOptions
resp.addHeader("Access-Control-Allow-Headers", "Content-Type,Origin,Accept,SOAPAction");

最后

这次总算是摸透了

资料参考

ajax跨域,这应该是最全的解决方案了