今天在慕課網上學習了AJAX跨域徹底講解:www.imooc.com/learn/947html
我在收集AJAX面試題的時候其實就已經有過AJAX跨域的問題的了,當時候知道了爲何會存在跨域,以及跨域解決的方案有哪些,今天隨着課程的學習,又加深了AJAX跨域的理解,以此記錄下來。前端
上面的圖也很清晰了,由於瀏覽器爲了安全(同源),自己就限制了。java
值得注意的是:跨域的問題是發生在XMLHttpRequest請求的,也就是說,不是XMLHttpRequest請求是不會有跨域問題的nginx
<img = src = www.xxxx.xxxx/ >
,URL不是本域的仍是能夠正常獲取該圖片的明顯地,跨域的問題是因爲瀏覽器限制的,是XMLHttpRequest纔會發生的,那麼咱們能夠以這個思路去找找解決思路:面試
對於瀏覽器的問題,可使用相關的參數進行啓動瀏覽器,是能夠解決跨域的問題,可是通用性是極低的,瞭解便可。ajax
JSONP是JSON使用的一種補充方式,不是官方的協議。JSONP是一種解決跨域問題的一種協議spring
JSONP這種解決方案其實如今已經不多用了(複雜一點,須要修改後臺代碼),但咱們能夠適當瞭解一下。apache
在後端增長一個控制器,繼承AbstractJsonpResponseBodyAdvice類,完整代碼以下:json
@ControllerAdvice public class JsonpAdvice extends AbstractJsonpResponseBodyAdvice { public JsonpAdvice() { // TODO Auto-generated constructor stub super("callback2"); } }
前端ajax請求:segmentfault
// 服務器返回的結果 var result; $.ajax({ url: base +"/get1", dataType: "jsonp", jsonp: "callback2", //是否須要緩存,若是這裏沒有配置緩存,那麼請求的URL還會有一個參數 cache:true, success: function(json){ result = json; } });
注意的是,前端AJAX的jsonp: "callback2",
要和咱們的Controllersuper("callback2");
是一致的,否則是不會有效的。
JSONP原理是動態建立script來進行請求的:
JSONP的弊端:
參考資料:
CORS解決跨域問題(也就是咱們服務端被調用方解決跨域的思路)
對於CORS是怎麼理解的,我就直接摘抄一下:segmentfault.com/a/119000001…的了。
在Java中,咱們寫下面這個過濾器,就能夠徹底解決跨域的問題了:
package com.imooc; import java.io.IOException; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.tomcat.util.buf.StringUtils; public class CrosFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { // TODO Auto-generated method stub } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { // TODO Auto-generated method stub HttpServletResponse res = (HttpServletResponse) response; HttpServletRequest req = (HttpServletRequest) request; //帶cookie的時候,origin必須是全匹配,不能使用* String origin = req.getHeader("Origin"); if (!org.springframework.util.StringUtils.isEmpty(origin)) { res.addHeader("Access-Control-Allow-Origin", origin); } res.addHeader("Access-Control-Allow-Methods", "*"); // 支持全部自定義頭和預檢命令(非簡單請求會有預檢命令) String headers = req.getHeader("Access-Control-Request-Headers"); if (!org.springframework.util.StringUtils.isEmpty(headers)) { res.addHeader("Access-Control-Allow-Headers", headers); } res.addHeader("Access-Control-Max-Age", "3600"); // enable cookie res.addHeader("Access-Control-Allow-Credentials", "true"); chain.doFilter(request, response); } @Override public void destroy() { // TODO Auto-generated method stub } }
上面提到了非簡單請求,那什麼是非簡單請求呢,能夠看下面的圖:
非簡單請求會發出一個預檢命令的(固然了,咱們上面的Filter已經解決預檢命令的問題了):
若是使用的是Spring框架的話,那就只須要一個註解就可以解決跨域的問題了:@CrossOrigin
咱們在的商用開發中,通常請求的過程是這樣的:瀏覽器->HTTP服務器(Nginx,Apache)->應用服務器(Tomcat,Weblogic)
上面編寫的Filter、Spring框架都是在應用服務器上解決的,咱們也是能夠經過HTTP服務器(Nginx,Apache)來進行解決跨域問題的!
Nginx我用過,Apache我卻是還沒用過,下面就簡單記錄了Nginx和Apache是如何配置的:
Nginx配置:
Apache配置:
在以前的圖咱們已經看到了,解決跨域的問題能夠在「調用方」中來進行解決。
「調用方」解決跨域的問題是這個思路的:讓發送出去的請求代理成是本域的
舉個例子:
www.zhongfucheng.top是調用方 www.zhongfucheng.site是被調用方
它倆是不一樣域的,但咱們能夠在nginx或Apache上進行配置代理:將被調用方www.zhongfucheng.site映射成別的路徑
好比,像下面的圖,將8080端口的映射成了ajaxServer,當調用方訪問ajaxServer路徑時,這樣的方法在外部看起來就不像是跨域了,像是訪問本地(8081端口),但實際訪問別的域(8080端口)
令我感到最簡單的是經過Spring的註解就能夠解決跨域的問題了,JSONP的方式已是不多用的了,由於存在必定的弊端,但瞭解一下也無妨,畢竟可能面試的時候會問到。當沒有用任何框架的時候,寫Filter也不麻煩,也只是配置了一下HTTP頭信息而已。若是使用Nginx、Apache時,也能夠用代理或者配置HTTP頭信息均可以解決。看完以後,有沒有以爲跨域問題就迎刃而解了。
若是文章有錯的地方歡迎指正,你們互相交流。習慣在微信看技術文章的同窗,想要獲取更多的Java資源的同窗,能夠關注微信公衆號:Java3y