1. 程式人生 > >跨域解決辦法

跨域解決辦法

        隨著軟體開發分工趨於精細,前後端開發分離成為趨勢,前端同事負責前端頁面的展示及頁面邏輯處理,服務端同事負責業務邏輯處理同時通過API為前端提供資料也為前端提供資料的持久化能力,考慮到前後端同事開發工具和習慣的不同,必然需要將前後端專案進行獨立,再者考慮到網站訪問速度的問題,需要將靜態資源部署到CDN伺服器上這樣專案分離也成為了必然。然而專案分離部署分離帶來的問題就是跨域請求的問題,本例對比較流行的兩種跨域訪問方式(Jsonp和CORS)進行討論。

一、簡要介紹

1.JSONP

   JSONP是利用瀏覽器對script的資源引用沒有同源限制,通過動態插入一個script標籤,當資源載入到頁面後會立即執行的原理實現跨域的。JSONP是一種非正式傳輸協議,該協議的一個要點就是允許使用者傳遞一個callback或者開始就定義一個回撥方法,引數給服務端,然後服務端返回資料時會將這個callback引數作為函式名來包裹住JSON資料,這樣客戶端就可以隨意定製自己的函式來自動處理返回資料了。
  JSONP只支援GET請求而不支援POST等其它型別的HTTP請求,它只支援跨域HTTP請求這種情況,不能解決不同域的兩個頁面之間如何進行JavaScript呼叫的問題,JSONP的優勢在於支援老式瀏覽器,弊端也比較明顯:需要客戶端和服務端定製進行開發,服務端返回的資料不能是標準的Json資料,而是callback包裹的資料。

2.CORS

       CORS是現代瀏覽器支援跨域資源請求的一種方式,全稱是"跨域資源共享"(Cross-origin resource sharing),當使用XMLHttpRequest傳送請求時,瀏覽器發現該請求不符合同源策略,會給該請求加一個請求頭:Origin,後臺進行一系列處理,如果確定接受請求則在返回結果中加入一個響應頭:Access-Control-Allow-Origin;瀏覽器判斷該相應頭中是否包含Origin的值,如果有則瀏覽器會處理響應,我們就可以拿到響應資料,如果不包含瀏覽器直接駁回,這時我們無法拿到響應資料。
  CORS與JSONP的使用目的相同,但是比JSONP更強大,CORS支援所有的瀏覽器請求型別,承載的請求資料量更大,開放更簡潔,服務端只需要將處理後的資料直接返回,不需要再特殊處理。

二、跨域具體解決方案

1.JSONP解決方案

前端:
$.ajax({
     url: "http://otherdomain.com/manage/role/get",
     async: false,
     type: "get", 
     dataType: "jsonp",
     data:{
        "id":1 
     },
     jsonp: "callback",
     jsonpCallback:"fn",
     success: function(data){
         alert(data.code);
     },
     error: function(){
         alert('fail');
     }
})

後端:

@RequestMapping("/manage/role/get")
@ResponseBody
public String get(HttpServletRequest request, HttpServletResponse response) {
    BaseOutput outPut = new BaseOutput();
    try {
        QueryFilter filter = new QueryFilter(request);
        logger.info(filter.toString());
        String id = filter.getParam().get(MainConst.KEY_ID);
        if(!StringUtil.isEmpty(id)) {
            ImRole role = roleService.getByPk(filter);
            outPut.setData(role);
        }
        else {
            outPut.setCode(OutputCodeConst.INPUT_PARAM_IS_NOT_FULL);
            outPut.setMsg("The get id is needed.");
        }
    } catch (Exception e) {
        logger.error("獲取角色資料異常!", e);
        outPut.setCode(OutputCodeConst.UNKNOWN_ERROR);
        outPut.setMsg("獲取角色資料異常! " + e.getMessage());
    }
    return "fn("+JsonUtil.objectToJson(outPut)+")";
}

注意:

1.1Ajax請求需要設定請求型別為Jsonp

dataType: "jsonp"

1.2Ajax請求需要設定回撥函式,當前函式值必須與伺服器響應包含的callback名稱相同

jsonpCallback:"fn"

1.3Ajax請求可以設定jsonp(可選),傳遞給請求處理程式或頁面,用以獲得jsonp回撥函式名的引數名,預設為:callback

jsonp: "callback"

1.4服務端返回Json資料必須使用jsonpCallback設定的值進行包裹

return "fn("+JsonUtil.objectToJson(outPut)+")"

2.CORS方案實現跨域

前端:
function test() {
   $.ajax({
         url: "http://localhost:8080/AdsServer/manage/role/get",
         type: "get",
         async: false,
         data:{
            "id":1 
         },
         dataType:"json",
         withCredentials:true,
         success: function(data){
             alert(data);
             alert(data.code);
         },
         error: function(){
             alert('fail');
         }
   })
}

後端:

@RequestMapping("/manage/role/get")
@ResponseBody
public String get(HttpServletRequest request, HttpServletResponse response) {
    BaseOutput outPut = new BaseOutput();
    try {
        QueryFilter filter = new QueryFilter(request);
        logger.info(filter.toString());
        String id = filter.getParam().get(MainConst.KEY_ID);
        if(!StringUtil.isEmpty(id)) {
            ImRole role = roleService.getByPk(filter);
            outPut.setData(role);
        }
        else {
            outPut.setCode(OutputCodeConst.INPUT_PARAM_IS_NOT_FULL);
            outPut.setMsg("The get id is needed.");
        }
    } catch (Exception e) {
        logger.error("獲取角色資料異常!", e);
        outPut.setCode(OutputCodeConst.UNKNOWN_ERROR);
        outPut.setMsg("獲取角色資料異常! " + e.getMessage());
    }
    return JsonUtil.objectToJson(outPut);
}
服務端增加過濾攔截器(web.xml)
<filter>
    <filter-name>crossDomainFilter</filter-name>
    <filter-class>com.luwei.core.filter.CrossDomainFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>crossDomainFilter</filter-name>
    <url-pattern>*</url-pattern>
</filter-mapping>

服務端增加過濾攔截器(java)

package com.luwei.core.filter;

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.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.luwei.console.mg.constant.ApplicationConfiConst;

/**
 * 
 * <Description> TODO<br> 
 *  
 * @author lu.wei<br>
 * @email [email protected] <br>
 * @date 2017年1月4日 <br>
 * @since V1.0<br>
 * @see com.luwei.console.mg.tag <br>
 */
public class CrossDomainFilter implements Filter {
    private Logger logger = LoggerFactory.getLogger(getClass());

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        ApplicationConfiConst confiConst = (ApplicationConfiConst) ContextUtil.getBean("applicationConfiConst");
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        String referer = request.getHeader("referer");
        String origin = null;
        if (null != referer) {
            String[] domains = confiConst.getCanAccessDomain().split(",");
            for (String domain : domains) {
                if (StringUtils.isNotEmpty(domain) && referer.startsWith(domain)) {
                    origin = domain;
                    break;
                }
            }
        }
        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");

        String requestURI = ((HttpServletRequest) req).getRequestURI();
        long begin = System.currentTimeMillis();
        chain.doFilter(req, res);
        if (logger.isDebugEnabled()) {
            logger.debug("[Request URI: " + requestURI + "], Cost Time:" + (System.currentTimeMillis() - begin) + "ms");
        }
    }
}
增加設定能夠通過跨域訪問的伺服器地址
#設定能夠訪問介面的域(多個通過都好分割)(不能配置127.0.0.1)
CAN_ACCESS_DOMAIN=http://localhost:8020,http://localhost:9999,http://localhost:8080

注意內容:

2.1Ajax請求必須要設定withCredentials屬性為true

withCredentials:true

2.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");

2.3withCredentials設定成true時,Access-Control-Allow-Origin不支援通過*的方式進行統配

2.4Access-Control-Allow-Origin不能直接配置多個請求伺服器,但是可以通過靜態配置多個的方式,然後根據referer匹配,匹

配到哪個則設定Access-Control-Allow-Origin為哪個的方式來配置多個

後記:

jqGrid配置跨域請求的方式為:

ajaxGridOptions: {
    xhrFields: {
        withCredentials: true
    }
},

相關推薦

ajax解決辦法

跨域的安全限制都是指瀏覽器端來說的.伺服器端是不存在跨域安全限制的, 什麼是跨域: 跨域是指從一個域名的網頁去請求另一個域名的資源。比如從www.baidu.com 頁面去請求 www.google.com 的資源。跨域的嚴格一點的定義是:只要 協議,域名,埠有任何一

iFrame解決辦法

按情境分 1、不跨域時 2、主域相同、子域不同時 3、主域不同 不跨域時 訪問iframe: contentWindow 訪問父級:parent 訪問頂級:top  a.html  <html xmlns="http://www.w3.org/1999/xhtm

關於iFrame特性總計和iFrame解決辦法

1、iframe 定義和用法 iframe 元素會建立包含另外一個文件的內聯框架(即行內框架)。 HTML 與 XHTML 之間的差異 在 HTML 4.1 Strict DTD 和 XHTML 1.0 Strict DTD 中,不支援 iframe 元素。 提示和註釋: 提示:您可以把需要的文字放

Django2.x前後端分離開發,解決辦法

安裝django-cors-headers pip3 install django-cors-headers # 安裝django-cors-headers 在專案目錄裡面的settings.py新增下面的程式碼 INSTALLED_APPS = [ ... 'corsh

vue中解決辦法

專案在上線之後,前後端的程式碼放在同一個伺服器下面,就不存在跨域的問題。然而在前後端分離的開發中,跨域在所難免。在以前,存在跨域的時候一般都叫後臺小夥伴設定,但是vue中提供了一種方法,在前端也可以設定解決跨域的問題。下面給大家介紹一下: 一、修改config資料夾中i

前端解決辦法之JSONP

由於JavaScript的同源策略限制,在當前JavaScript指令碼中並不能操作來自非同一域下的資源,這就使得跨域問題之於前端工程師就像彈吉他之於民謠歌手——是非常重要的基本功。 跨域問題解決辦法有很多種,比如W3C給出的CORS(Cross-Origin Resour

SpringBoot+Spring Security無法實現解決辦法

未使用Security時跨域: import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframewor

解決辦法

        隨著軟體開發分工趨於精細,前後端開發分離成為趨勢,前端同事負責前端頁面的展示及頁面邏輯處理,服務端同事負責業務邏輯處理同時通過API為前端提供資料也為前端提供資料的持久化能力,考慮到前後端同事開發工具和習慣的不同,必然需要將前後端專案進行獨立,再者考慮到網站訪

WebApi中解決辦法

在做Web開發中,常常會遇到跨域的問題,到目前為止,已經有非常多的跨域解決方案。由於時間有限,本文不會深入。 筆者遇到的問題是Js呼叫WebAPI中的資料進行跨域的場景。涉及若干跨域方案: 方案1:jsonp+回撥 方案2:Microsoft.AspNet.WebApi.Cors提供的跨域屬性 方案3:利

前端解決辦法(待整理)

重點記住的有:domain+iframe , jsonp , poseMessage , webSocket  伺服器端跨域有:ngix反向代理,設定Access-Control-Allow-Origin 待實踐。。。

javascript同源策略和實驗及其解決辦法

二、問題分析: 應用A採用域名http://trade.alibaba.com ,應用B採用的域名 http://56.alibaba.com。屬於相同主域下的不同子域。牽涉出跨域是否能操作其他文件三、問題延伸: 瞭解跨域,我們先了解一下javascript的同源策略,同源策略阻止從一個源載入的文件或指令

解決ajax辦法,代理,cors,jsonp

resource 通過 使用 -o 參考 acc log 方式 sha 1、使用php做代理去請求第三方api接口 php是可以跨域的,我們利用ajax請求本域名中的php文件,php再去請求第三方接口文件,從而達到跨域目的。 php做代理請求: aj

JSON解決方案收集

get ogl obb 本地 allow con mesa 跨域請求 loader 最近面試問的挺多的一個問題,就是JavaScript的跨域問題。在這裏,對跨域的一些方法做個總結。由於瀏覽器的同源策略,不同域名、不同端口、不同協議都會構成跨域;但在實際的業務中,很多

前端如何去做解決方案

時也 for 前後端 define 影響 list nts 告訴 iframe 前言 那些你,你常用的跨域解決方案除了jsonp 之外,還有其他的嗎?今日早讀文章可以告訴你,本文由 金蝶 @scq000授權分享。 正文從這開始~ 瀏覽器在請求不同域的資源時,會因為同源策略的

前端常見解決方案(全)

-type crm api war str bsp 斷開 jquery 數據塊 什麽是跨域? 跨域是指一個域下的文檔或腳本試圖去請求另一個域下的資源,這裏跨域是廣義的。 廣義的跨域: 1.) 資源跳轉: A鏈接、重定向、表單提交 2.) 資源嵌入: <link

前端常見解決方案

自定義 兩個 ech cors onload 消息 strong put 普通 什麽是跨域? 跨域是指一個域下的文檔或腳本試圖去請求另一個域下的資源,這裏跨域是廣義的。 廣義的跨域: 1.) 資源跳轉: A鏈接、重定向、表單提交 2.) 資源嵌入:<lin

withCredentials--相同主解決方法

rip bsp keyword 不同 plain script mode nbsp 主域 主域相同,而子域不同,存在跨域問題。在高版本瀏覽器下,可以設置withCredentials來解決。   xhrFields: {withCredentials: true}   低版

關於Vue-cli的解決

tar bsp es2017 dex 前綴 成功 config 端口 log 由於Vue-cli服務器是跑在node環境下的8080端口,我們的php代碼可能在Apache環境下的7070端口,這個時候就會出現跨域 此刻這段php代碼在7070端口上 如果直接去訪問

spring mvc的解決方案

增加 是否 strac inf oss ref nds sso option 什麽是跨域 一句話:同一個ip、同一個網絡協議、同一個端口,三者都滿足就是同一個域,否則就是跨域。 為什麽非得跨域 基於兩個方面: a. web應用本身是部署在不同的服務器上 b.基於開發的角度

vue解決方法 及設置api路徑方法

fun tab cti query 跨域請求 geo var nco target vue項目中,前端與後臺進行數據請求或者提交的時候,如果後臺沒有設置跨域,前端本地調試代碼的時候就會報“No ‘Access-Control-Allow-Origin‘ header is