1. 程式人生 > >跨域方式 jsonp cors

跨域方式 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