AJAX跨域總結

       螞蟻金服的實習即將結束,將知識總結一下。javascript

       咱們這個項目前端使用antD,antD是採用React封裝的一套組件庫,目前開源http://ant.design/,全部組件都是拿來即用,大大縮短了開發週期,強烈推薦。React是單頁面應用,經過ajax與後臺通訊,而antD調試部署在8000端口,後臺又是運行在另外一個端口,先後臺通訊跨域。AJAX跨域通常有兩種解決方法:CORS(跨域資源共享)和JSONP。前端

       先來看看JSONP,本質原理利用script標籤src屬性能夠跨域的特性,咱們本身也能夠去實現JSONP,動態添加刪除script標籤:java

function loadJs() {
  var script = document.createElement("script");
  script.src = "http://xxxxxx/get/req";
  document.body.appendChild(script);
    
  script.onload = function() {
    callback(); 
    document.body.removeChild(script);
  }
}

       在AJAX中使用JSOP:ajax

$.ajax({
   url: 'http://xxxxxx/get/req', 
   cache: false,
   type: 'post',
   jsonp:'callback',
   dataType:'jsonp', 
   success: function (result) {
      //處理結果的過程
   },
   error: function (XMLHttpRequest) {
      //出錯回調處理
   }
});

       相應的後臺代碼:json

/**
	 * 測試
	 * 
	 * @throws IOException
	 */
	@RequestMapping("/get/req")
	@ResponseBody
	public void getData(HttpServletRequest req, HttpServletResponse rep) throws IOException {
		Map<String, Object> result = null;
		result = manager.getDatas();
		String callback = req.getParameter("callback");
		String json = JSONObject.toJSONString(result);
		rep.setContentType("text/javascript");
		rep.setCharacterEncoding("utf-8");
		PrintWriter out = rep.getWriter();
		out.print(callback + "(" + json + ")");
	}

       CORS分爲簡單請求和非簡單請求,非簡單請求的請求方法不是POST、GET、HEAD,或者header中包含一些特殊請求頭,以及Content-Type不是application/x-www-form-urlencoded、multipart/form-data、text/plain的請求。向後臺發送請求時會多發送一次option請求,而且不能攜帶cookie,這個後面再說。CORS只需服務器端在每次響應中設置一些響應頭便可,將這些操做放在Filter中實現低耦合:跨域

@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse rep = (HttpServletResponse) response;
        HttpServletRequest req = (HttpServletRequest) request;
        rep.addHeader("Access-Control-Allow-Origin", req.getHeader("Origin"));
        rep.setHeader("Access-Control-Allow-Credentials", "true");//跨域攜帶cookie
        rep.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");//非簡單請求
        rep.setContentType("application/json; charset=utf-8");
        rep.setHeader("Access-Control-Allow-Methods","GET,POST,PUT,DELETE");//非簡單請求
        chain.doFilter(request, rep);
    }

       咱們的項目須要接入統一登陸中心,SSO你們也知道,每次請求來了以後SSOClient判斷是否攜帶token,過時或者沒有token會重定向到登陸頁面讓用戶進行登陸。這裏出現了一個問題,前端向後臺發送AJAX請求,在用戶沒有登陸時並不能正常重定向到登陸中心,而是出現前臺到登陸中心頁面的XMLHttpRequest跨域錯誤提示。可是經過瀏覽器直接輸入後臺請求URL地址,在用戶沒有登陸時,會重定向到登陸中心頁面。對於這個問題的產生一開始沒有頭緒,進行了多種嘗試以後定位到了緣由。瀏覽器

       這裏涉及到瀏覽器是如何處理AJAX請求重定向,當服務器將302響應發給瀏覽器,瀏覽器並非直接進行AJAX回調處理,而是先執行302重定向,從Response Headers中讀取Location信息,而後向Location中的Url發出請求,在收到這個請求的響應後纔會進行AJAX回調處理。antD是個單頁面應用,先後臺交互經過AJAX的方式,因此當SSOFilter攔截ajax請求以後,瀏覽器會首先重定向到登錄中心,產生了前臺到登陸中心的跨域AJAX請求,當瀏覽器發現響應頭信息沒有包含Access-Control-Allow-Origin字段,從而拋出XMLHttpRequest cannot load的錯誤。服務器

       CORS請求默認不發送Cookie和http認證信息,若是要把Cookie發送到服務器,一方面須要服務器贊成,指定Access-Control-Allow-Credentials響應頭,另外一方面必須在AJAX中打開withCredentials屬性,$.ajaxSetup方法設置AJAX請求的默認參數選項,多個AJAX請求時,不用爲每個請求配置請求的參數:cookie

$.ajaxSetup({
   xhrFields: {
     withCredentials: true
   },
 })
相關文章
相關標籤/搜索