同源策略
- 協議相同
- 域名相同
- 端口相同
不同源的網頁之間,是無法互相訪問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/