跨域方式 jsonp cors
一、簡要介紹
1.1、JSONP
JSONP是利用瀏覽器對script的資源引用沒有同源限制,通過動態插入一個script標籤,當資源載入到頁面後會立即執行的原理實現跨域的。JSONP是一種非正式傳輸協議,該協議的一個要點就是允許使用者傳遞一個callback或者開始就定義一個回撥方法,引數給服務端,然後服務端返回資料時會將這個callback引數作為函式名來包裹住JSON資料,這樣客戶端就可以隨意定製自己的函式來自動處理返回資料了。
JSONP只支援GET請求而不支援POST等其它型別的HTTP請求,它只支援跨域HTTP請求這種情況,不能解決不同域的兩個頁面之間如何進行JavaScript呼叫的問題,JSONP的優勢在於支援老式瀏覽器,弊端也比較明顯:需要客戶端和服務端定製進行開發,服務端返回的資料不能是標準的Json資料,而是callback包裹的資料。
1.2、CORS
CORS是現代瀏覽器支援跨域資源請求的一種方式,全稱是"跨域資源共享"(Cross-origin resource sharing),當使用XMLHttpRequest傳送請求時,瀏覽器發現該請求不符合同源策略,會給該請求加一個請求頭:Origin,後臺進行一系列處理,如果確定接受請求則在返回結果中加入一個響應頭:Access-Control-Allow-Origin;瀏覽器判斷該相應頭中是否包含Origin的值,如果有則瀏覽器會處理響應,我們就可以拿到響應資料,如果不包含瀏覽器直接駁回,這時我們無法拿到響應資料。
CORS與JSONP的使用目的相同,但是比JSONP更強大,CORS支援所有的瀏覽器請求型別,承載的請求資料量更大,開放更簡潔,服務端只需要將處理後的資料直接返回,不需要再特殊處理。
二、跨域解決方案距離
2.1、JSONP方案實現跨域
前段AJAX請求
1 $.ajax({ 2 url: "http://otherdomain.com/manage/role/get", 3 async: false, 4 type: "get", 5 dataType: "jsonp", 6 data:{ 7 "id":1 8 }, 9 jsonp: "callback", 10 jsonpCallback:"fn", 11 success: function(data){ 12 alert(data.code); 13 }, 14 error: function(){ 15 alert('fail'); 16 } 17 })
服務端響應資料
1 @RequestMapping("/manage/role/get") 2 @ResponseBody 3 public String get(HttpServletRequest request, HttpServletResponse response) { 4 BaseOutput outPut = new BaseOutput(); 5 try { 6 QueryFilter filter = new QueryFilter(request); 7 logger.info(filter.toString()); 8 String id = filter.getParam().get(MainConst.KEY_ID); 9 if(!StringUtil.isEmpty(id)) { 10 ImRole role = roleService.getByPk(filter); 11 outPut.setData(role); 12 } 13 else { 14 outPut.setCode(OutputCodeConst.INPUT_PARAM_IS_NOT_FULL); 15 outPut.setMsg("The get id is needed."); 16 } 17 } catch (Exception e) { 18 logger.error("獲取角色資料異常!", e); 19 outPut.setCode(OutputCodeConst.UNKNOWN_ERROR); 20 outPut.setMsg("獲取角色資料異常! " + e.getMessage()); 21 } 22 return "fn("+JsonUtil.objectToJson(outPut)+")"; 23 }
注意內容:
1、Ajax請求需要設定請求型別為Jsonp
dataType: "jsonp"
2、Ajax請求需要設定回撥函式,當前函式值必須與伺服器響應包含的callback名稱相同
jsonpCallback:"fn"
3、Ajax請求可以設定jsonp(可選),傳遞給請求處理程式或頁面,用以獲得jsonp回撥函式名的引數名,預設為:callback
jsonp: "callback"
4、服務端返回Json資料必須使用jsonpCallback設定的值進行包裹
return "fn("+JsonUtil.objectToJson(outPut)+")"
2.2、CORS方案實現跨域
前段AJAX請求
1 function test() { 2 $.ajax({ 3 url: "http://localhost:8080/AdsServer/manage/role/get", 4 type: "get", 5 async: false, 6 data:{ 7 "id":1 8 }, 9 dataType:"json", 10 withCredentials:true, 11 success: function(data){ 12 alert(data); 13 alert(data.code); 14 }, 15 error: function(){ 16 alert('fail'); 17 } 18 }) 19 }
服務端響應資料
1 @RequestMapping("/manage/role/get") 2 @ResponseBody 3 public String get(HttpServletRequest request, HttpServletResponse response) { 4 BaseOutput outPut = new BaseOutput(); 5 try { 6 QueryFilter filter = new QueryFilter(request); 7 logger.info(filter.toString()); 8 String id = filter.getParam().get(MainConst.KEY_ID); 9 if(!StringUtil.isEmpty(id)) { 10 ImRole role = roleService.getByPk(filter); 11 outPut.setData(role); 12 } 13 else { 14 outPut.setCode(OutputCodeConst.INPUT_PARAM_IS_NOT_FULL); 15 outPut.setMsg("The get id is needed."); 16 } 17 } catch (Exception e) { 18 logger.error("獲取角色資料異常!", e); 19 outPut.setCode(OutputCodeConst.UNKNOWN_ERROR); 20 outPut.setMsg("獲取角色資料異常! " + e.getMessage()); 21 } 22 return JsonUtil.objectToJson(outPut); 23 }
服務端增加過濾攔截器(web.xml)
1 <filter> 2 <filter-name>crossDomainFilter</filter-name> 3 <filter-class>com.luwei.core.filter.CrossDomainFilter</filter-class> 4 </filter> 5 <filter-mapping> 6 <filter-name>crossDomainFilter</filter-name> 7 <url-pattern>*</url-pattern> 8 </filter-mapping>
服務端增加過濾攔截器(java)
1 package com.luwei.core.filter; 2 3 import java.io.IOException; 4 5 import javax.servlet.Filter; 6 import javax.servlet.FilterChain; 7 import javax.servlet.FilterConfig; 8 import javax.servlet.ServletException; 9 import javax.servlet.ServletRequest; 10 import javax.servlet.ServletResponse; 11 import javax.servlet.http.HttpServletRequest; 12 import javax.servlet.http.HttpServletResponse; 13 14 import org.apache.commons.lang.StringUtils; 15 import org.slf4j.Logger; 16 import org.slf4j.LoggerFactory; 17 18 import com.luwei.console.mg.constant.ApplicationConfiConst; 19 20 /** 21 * 22 * <Description> TODO<br> 23 * 24 * @author lu.wei<br> 25 * @email [email protected] <br> 26 * @date 2017年1月4日 <br> 27 * @since V1.0<br> 28 * @see com.luwei.console.mg.tag <br> 29 */ 30 public class CrossDomainFilter implements Filter { 31 private Logger logger = LoggerFactory.getLogger(getClass()); 32 33 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { 34 ApplicationConfiConst confiConst = (ApplicationConfiConst) ContextUtil.getBean("applicationConfiConst"); 35 HttpServletResponse response = (HttpServletResponse) res; 36 HttpServletRequest request = (HttpServletRequest) req; 37 String referer = request.getHeader("referer"); 38 String origin = null; 39 if (null != referer) { 40 String[] domains = confiConst.getCanAccessDomain().split(","); 41 for (String domain : domains) { 42 if (StringUtils.isNotEmpty(domain) && referer.startsWith(domain)) { 43 origin = domain; 44 break; 45 } 46 } 47 } 48 response.setHeader("Access-Control-Allow-Origin", origin); 49 response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE,PATCH"); 50 response.setHeader("Access-Control-Max-Age", "3600"); 51 response.setHeader("Access-Control-Allow-Headers", "x-requested-with"); 52 // 是否支援cookie跨域 53 response.addHeader("Access-Control-Allow-Credentials", "true"); 54 55 String requestURI = ((HttpServletRequest) req).getRequestURI(); 56 long begin = System.currentTimeMillis(); 57 chain.doFilter(req, res); 58 if (logger.isDebugEnabled()) { 59 logger.debug("[Request URI: " + requestURI + "], Cost Time:" + (System.currentTimeMillis() - begin) + "ms"); 60 } 61 } 62 }
增加設定能夠通過跨域訪問的伺服器地址
#設定能夠訪問介面的域(多個通過都好分割)(不能配置127.0.0.1) CAN_ACCESS_DOMAIN=http://localhost:8020,http://localhost:9999,http://localhost:8080
注意內容:
1、Ajax請求必須要設定withCredentials屬性為true
withCredentials:true
2、服務端需要配置過濾器,講配置能夠進行跨域訪問伺服器的地址進行配置
response.setHeader("Access-Control-Allow-Origin", origin); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE,PATCH"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "x-requested-with"); // 是否支援cookie跨域 response.addHeader("Access-Control-Allow-Credentials", "true");
3、withCredentials設定成true時,Access-Control-Allow-Origin不支援通過*的方式進行統配
4、Access-Control-Allow-Origin不能直接配置多個請求伺服器,但是可以通過靜態配置多個的方式,然後根據referer匹配,匹配到哪個則設定Access-Control-Allow-Origin為哪個的方式來配置多個
後記:
jqGrid配置跨域請求的方式為:
ajaxGridOptions: { xhrFields: { withCredentials: true } }, 轉自:https://www.cnblogs.com/banning/p/6250677.html