1. 程式人生 > >實踐解決跨域問題的三種方式剖析

實踐解決跨域問題的三種方式剖析

最近在做我星際schub網站的時候,遇到了跨域問題,我先把後端node部署在了伺服器上,然後在本地localhost測試,出現了問題:
這裡寫圖片描述

瀏覽器都提示我們使用這個header頭:

解決辦法:

1. CORS

伺服器設定響應頭:

response.setHeader("Access-Control-Allow-Origin", "*")

(這樣可能引起CSRF攻擊,一般設定成對應的域名就行,
response.setHeader("Access-Control-Allow-Origin", "http:localhost:8080/") )
fetch的option加上 mode:"cors"。

(需要注意的是,如果要傳送Cookie,Access-Control-Allow-Origin就不能設為星號,必須指定明確的、與請求網頁一致的域名。同時,Cookie依然遵循同源政策,只有用伺服器域名設定的Cookie才會上傳,其他域名的Cookie並不會上傳,且(跨源)原網頁程式碼中的document.cookie也無法讀取伺服器域名下的Cookie。)
關於CORS的講解,可以看阮一峰的這篇文章:

連結

2.jsonp

jsonp的方式,注意這種方式只能傳送get請求,就算指定為post,最後傳送的還是get,且跟上面方式一樣,也需要伺服器的配合支援。之前在做vue音樂播放器專案的時候,呼叫的是qq音樂的介面,qq音樂的介面返回的就是jsonp格式的
這裡寫圖片描述

1、 jsonp傳送的並不是ajax請求;
2、 利用動態建立一個script標籤,因為script標籤是沒有同源策略限制的,是可以跨域的;
3、 把這個script標籤的src指向我們請求的服務端地址,這個地址會攜帶一個引數:callback ,一個回撥函式,服務端會把資料通過這個回撥函式返回給客戶端,但是客戶端沒有這個函式怎麼接收呢?所以在傳送請求之前,要在全域性(window)註冊這樣一個方法,利用這個方法,來獲得資料;
4、 這個回撥函式名需要跟服務端約定好,是一致的。

如果讓我們用原生js實現一個jsonp,那就是這樣:

     <script>
         //指定的回撥函式
         function showData (result) {
             var data = JSON.stringify(result); //json物件轉成字串
             $("#text").val(data);
         }
 
         $(document).ready(function () {
 
             $("#btn").click(function () {
                 //向頭部輸入一個指令碼,該指令碼發起一個跨域請求
                 $("head").append("<script src='http://localhost:9090/student?callback=showData'><\/script>");
             });
 
         });
     </script>

後端一是獲取到前端傳過來的回撥函式名稱,二是獲取到資料,最後把資料用回撥函式包圍住,執行這個前端的這個回撥函式。我們就可以利用前端這個事先全域性註冊的回撥函式來顯示操作資料了。

用Java寫的後臺demo就是這樣:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
  response.setCharacterEncoding("UTF-8");
  response.setContentType("text/html;charset=UTF-8");

  //資料
  List<Student> studentList = getStudentList();


  JSONArray jsonArray = JSONArray.fromObject(studentList);
 String result = jsonArray.toString();

 //前端傳過來的回撥函式名稱
 String callback = request.getParameter("callback");
 //用回撥函式名稱包裹返回資料,這樣,返回資料就作為回撥函式的引數傳回去了
 result = callback + "(" + result + ")";

 response.getWriter().write(result);
}

這裡再分析一下jQuery關於jsonp的實現。

1.最簡單的方式:

   $.ajax({
            type:"GET",
            url:"http://www.xxx.com/getMySeat", //訪問的連結
            dataType:"jsonp",  //資料格式設定為jsonp
            success:function(data){  //成功的回撥函式
                alert(data);
            },
            error: function (e) {
                alert("error");
            }
        });

服務端程式碼不變,最簡單的方式,只需配置一個dataType:'jsonp',就可以發起一個跨域請求。jsonp指定伺服器返回的資料型別為jsonp格式,可以看發起的請求路徑,自動帶了一個callback=xxx,callback是自己不手動設定引數名字的預設值,xxx是jquery隨機生成的一個回撥函式名稱。
這裡的success就跟上面的showData一樣,如果有success函式則預設success()作為回撥函式。

2.回撥函式你可以寫到script下(預設屬於window物件),或者指明寫到window物件裡,看jquery原始碼,可以看到jsonp呼叫回撥函式時,是呼叫的window.callback。
然後看呼叫結果,發現,請求時帶的引數是:callback=showData;呼叫回撥函式的時候,先呼叫了指定的showData,然後再呼叫了success。所以,success是返回成功後必定會呼叫的函式,就看你怎麼寫了。
指定回撥函式名稱,加一個option欄位即可:
這裡寫圖片描述
最後還是會呼叫success:
這裡寫圖片描述

  1. 如何改變callback這個預設值(回撥函式名稱的key值),在jq裡:
    這裡寫圖片描述
    這樣一改之後,響應的後端程式碼也要改動了,獲取的欄位key值就是theFunction了,
    這裡寫圖片描述
    對應的請求路徑也就變了:
    這裡寫圖片描述

除了jq對jsonp的實現,在上面提到的vue音樂播放器專案中,我使用了jsonp npm包,用這個包,就不需要自己在window上註冊回撥函式,qq音樂介面中jsonpCallback就是服務端返回的回撥函式(a方法) 我們本地在window上註冊的a方法是在呼叫的jsonp庫中自動被實現。我們自己寫成promise的方法後直接then即可。

但是後來我又遇到一個問題,schub星際網站專案中我想呼叫WCS職業聯賽積分賽排名的介面的時候,用fetch當然還是提示跨域問題了,這時候後端我又不能修改,所以CORS方式肯定不行,jsonp的方式也需要後端配合支援,上面兩種方法都不適用了。下面就是最終解決問題的第三種方法。

  1. 代理伺服器,跨域問題是瀏覽器的同源策略限制,伺服器之間是沒有的,那我們先把請求給我們的代理伺服器,再讓我們的代理伺服器去呼叫這個介面,在傳送給前端就可以了。

前端:
這裡寫圖片描述

代理伺服器(node):
這裡寫圖片描述

注意伺服器返回的資料在response.data裡,然後傳送給前端的響應res。
(後來我前後端設定的埠不同,代理伺服器也要設定Access-Control-Allow-Origin的頭為 *)

4.第四點我想談下不同跨域方式中關於cookie的。

在後面的部落格將會談到cookie再跨域中的問題。

相關推薦

實踐解決問題的方式剖析

最近在做我星際schub網站的時候,遇到了跨域問題,我先把後端node部署在了伺服器上,然後在本地localhost測試,出現了問題: 瀏覽器都提示我們使用這個header頭: 解決辦法: 1. CORS 伺服器設定響應頭: response.setHeader("Access-Control-Allow-

前端方式

div ner dev 修改 ati hash 標簽 nbsp 端口 跨域問題的直接原因是瀏覽器存在同源策略,瀏覽器同源指的是:兩個頁面的協議、端口和主機相同,則兩個頁面具有相同的源。IE下滿足協議、主機相同,就認為是同源。 想象一下,如果沒有同源策略,誰都可以修改你站點

php ajax jsonp 方式

第一種方式客戶端程式碼案例 第一種方法重點是服務端加header頭------》header("Access-Control-Allow-Origin: *"); 客戶端程式碼 header("Access-Control-Allow-Origin: *"); $data = $r

方式

一、什麼是跨域 JavaScript出於安全方面的考慮,不允許跨域呼叫其他頁面的物件。那什麼是跨域呢,簡單地理解就是因為JavaScript同源策略的限制, a.com 域名下的js無法操作 b.com 或是 c.a.com 域名下的物件。 有一點必須要注意:

解決Ajax請求的方式

如何解決跨域問題 什麼叫跨域: 主機、協議、埠三者有任何一個不同即為跨域 1. JSONP   JSONP是JSON with Padding的略稱。它是一個非官方的協議,它允許在伺服器端整合Script tags返回至客戶端,通過javascript call

伺服器端解決問題的方法

跨域是指html檔案所在的伺服器與ajax請求的伺服器是不同的ip+port,例如:  - ‘192.168.1.1:8080’ 與 ‘192.168.1.2:8080’是不同的域。  - ‘192.168.1.1:8080’ 與 ‘192.168.1.1:8081’是不同的域。

實現方式

  1、CorsFilter       過濾器   2、<mvc:cors>    Bean   在srping-web中配置   3、@CorssOrigin   註解   CorsFilter的實現    1 p

問題:解決方案

當前端頁面與後臺執行在不同的伺服器時,就必定會出現跨域這一問題,本篇簡單介紹解決跨域的三種方案,部分程式碼截圖如下,僅供參考:方式一:使用ajax的jsonp 前端程式碼  伺服器程式碼  使用該方式的缺點:請求方式只能是get請求方式二:使用jQuery的jsonp外掛

JavaWeb解決的兩方式

如果使用了SpringMVC,那麼只需要使用Filter就可以實現,此時需要使用@ResponseBody註解。package com.navercorp.pinpoint.web.filter; import javax.servlet.*; import javax.servlet.Filter; im

徹底解決問題(五解決方式)

跨域問題解決方案 最近自己寫了一個js元件,該js元件是提供給第三方使用的,而js元件中涉及了ajax請求,於是乎就出現了跨域請求問題。下面記錄一下自己的解決路程。 什麼是跨域 參考:跨域請求詳解 個人理解:我理解的跨域就是,兩個不同

解決方法

跨域 -o head 反向 content nbsp ces methods 函數 1.jsonp 目標服務器設置callback 函數 服務器操作 2.cors 服務器設置header :Access-Control-Allow-Origin 服務器操作

分散式鎖解決併發的實現方式

分散式鎖解決併發的三種實現方式 在很多場景中,我們為了保證資料的最終一致性,需要很多的技術方案來支援,比如分散式事務、分散式鎖等。有的時候,我們需要保證一個方法在同 一時間內只能被同一個執行緒執行。在單機環境中,Java中其實提供了很多併發處理相關的API,但是這些API在分散式場景中就無能

docker入門實戰(理論+實踐)系列---進入docker的方式

對於執行的docker容器,我們有三種方式進入docker容器內部,但三種方式存在不同的區別,且在生成環境中,慎用進入docker的方式非常有必要 1、docker attach進入docker容器 對於執行在後臺的docker容器,我們經常需要做的事情是進入到容器中,docker為我們提供了dock

“姿勢” 讓你徹底解決問題

轉載自:https://segmentfault.com/a/1190000016653873   同源策略 同源策略/SOP(Same origin policy)是一種約定,由 Netscape 公司 1995 年引入瀏覽器,它是瀏覽器最核心也最基本的安全功能,如果缺少了同

前後端分離,解決問題及django的csrf站請求保護 ajax headers JavaScript ajax 請求 +設定headers 實踐

1. 前後端分離解決跨域問題 解決跨域呼叫服務並設定headers 主要的解決方法需要通過伺服器端設定響應頭、正確響應options請求,正確設定 JavaScript端需要設定的headers資訊 方能實現; 關於跨域,前端會先發送OPTIONS請求,進行預檢,檢查後端是否允許前端設定的相應的請求頭,請

Jersey 實踐:構建RESTful服務及解決問題

最近在準備為我的小程式做個後臺,剛好之前在網上了解了RESTful這種設計風格,覺得很簡單輕量,便準備採用這種設計方式。有很多框架都能支援RESTful的設計,在一番權衡之後,決定選擇jersey框架,因為我的小程式的併發量並不大,而且自己對於spring也還不太熟悉,而je

方式解決vue中v-html元素中標籤樣式

當我們引入第三方元件或載入html元素時,想修改下樣式,就可以用以下三種方式: 一.去掉<style scoped>中的scoped 這個方法不建議使用,會改變佈局 二.定義兩個style標籤,一個含有scoped屬性,一個不含有scoped屬性 使用方法為 <

python pip install xxxx 中文路徑導致安裝庫時報錯問題解決方式

報錯內容:UnicodeDecodeError: ‘ascii’ codec can’t decode byte 0xd3 in position 7: ordinal not in range(128) 解決方案: 1.第一種辦法 在pycharm中開啟檔案(pyt

JS問題以及採用JSONP方式解決問題

在做專案的時候,客戶要做成客戶端和服務端兩部分,客戶端向服務端進行認證,我開始的時候沒有直接替換ip地址,後來採用ip地址替換之後,出現了問題,後臺可以收到訪問的請求,但是無法拿到後臺返回的資訊,後來

解決的兩方案

一、跨域與同源策略 跨域,通俗地講,是指一個服務A的客戶端請求另一個服務B的資料。下面給出了跨域的圖示。 在上面這個圖中,描述了客戶端與服務A關係,也就是說,客戶端不允許對服務A以外的服務進行訪問。這就是典型的跨域問題。通常同源策略與跨域緊密聯絡在一起。同源策略,它是由Netscape