螞蟻金服的實習即將結束,將知識總結一下。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 }, })