同源策略
- 协议相同
- 域名相同
- 端口相同
不同源的网页之间,是无法互相访问cookie、LocalStorage、indexDB的。
大家经常说的跨域访问,CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。http://www.ruanyifeng.com/blog/2016/04/cors.html
跨域访问时,如果客户端发送非简单请求,客户端会首先发送一个option预请求,检查服务端是否支持跨域访问。
客户端
一般客户端指的是常见的浏览器。
1、使用原生XMLHttpRequest方式实现跨域访问:
var xhr = new XMLHttpRequest(); xhr.onreadystatechange=processResponse; xhr.open("POST", "http://xxx.com/demo/index.php", true); xhr.withCredentials = true; //支持跨域发送cookies xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded"); xhr.send("id=1");
当跨域访问需要传输被访问域的cookie信息时,设置“xhr.withCredentials = true; ”,此时注意服务端的response header中也要增加header("Access-Control-Allow-Credentials: true"),具体原因稍后说明。
2、使用<script>标签方式实现
var url = "http://xxx.com/demo/index.php?callback=callbackFunction"; var script = document.createElement('script');// 创建script标签,设置其属性 script.setAttribute('src', url); document.getElementsByTagName('head')[0].appendChild(script);// 把script标签加入head,此时调用开始
“callbackFunction”为需要回掉执行的函数,返回的是可执行的javscript代码中以调用的方式出现,例如
callbackFunction({"name":"haha"})
使用script标签实现跨域,会同时将目的域的cookie一并传输。
3、使用jquery的jsonp请求实现跨域访问:
$.ajax({ type: "get", dataType: "jsonp", url: 'http://xxx.com/demo/index.php', // jsonp: 'callback', //回调函数参数名 // jsonpCallback: "callbackFunction",//用户定义的callback函数,没有定义的话会jQuery会自动生成以jQuery开头的函数名 success: function (json) { alert(json); } });
使用jsonp方式实现看跨域,同使用<script>标签的方式一样。
如果指定了jsonpCallback,就不会执行success方法了;没有指定jsonpCallback,会执行success。
注意,服务器返回的数据必须是可执行的javascript,使用指定的callback方法调用
// 如果指定了jsonpCallback为callbackFunction,返回应为是 callbackFunction({"name":"haha"}) // 如果没有指定jsonpCallback,返回结果可能是 jQuery112403687357423576312_1487056485968({"name":"haha"})
4、使用jquery的普通ajax请求,实现跨域
$.ajax({ type: "get", url: 'http://localhost/isv', xhrFields: { withCredentials: true }, //支持跨域发送cookie success: function (json) { alert(json); } });
如果需要跨域发送cookie,增加xhrFields: { withCredentials: true },此时注意服务端的response header中也要增加header("Access-Control-Allow-Credentials: true"),具体原因稍后说明。
服务端[1]
需要跨域调用的url,在其返回的response header中,需要增加
httpResponse.addHeader("Access-Control-Allow-Origin", "*");
代表响应所有跨域请求,多个值的话使用"|"分隔。如果response header中没有此设置,浏览器在响应成功后,会阻止回调函数执行,抛出错误。
如果需要跨域访问,request header中有cookie信息,并且
{ withCredentials: true }
服务端的response header中,需要增加
httpResponse.addHeader("Access-Control-Allow-Origin", "http://abc.com"); httpResponse.addHeader("Access-Control-Allow-Credentials", "true");
Access-Control-Allow-Origin不能再使用通配符。
tomcat实践
web.xml中增加
<filter> <filter-name>CorssFilter</filter-name> <filter-class>com.abc.filter.CrossFilter</filter-class> </filter> <filter-mapping> <filter-name>CorssFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
编写指定的filter
import javax.servlet.*; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class CrossFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletResponse httpResponse = (HttpServletResponse) servletResponse; httpResponse.addHeader("Access-Control-Allow-Origin", "*"); // httpResponse.addHeader("Access-Control-Allow-Credentials", "true"); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }
[1]. https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS
[2]. http://api.jquery.com/jquery.ajax/