學習AJAX必知必會(5)~同源策略、解決跨域問題(JSONP、CORS)

一樂樂發表於2022-01-22

一、同源策略(Same-Origin Policy),是瀏覽器的一種安全策略.

1、同源(即url相同):協議、域名、埠號 必須完全相同。(請求是來自同一個服務)

2、跨域:違背了同源策略,即跨域。

3、ajax請求是遵循同源策略的。

■ 同源請求例子(在瀏覽器訪問127.0.0.1:9000/server-orign,然後點選按鈕傳送同源請求):

  • 服務端對同源請求處理:

    //3、建立路由規則(request 是請求的報文,response是響應的報文)
    app.get('/server-orign', (request, response) => {
        //響應一個頁面
        response.sendFile(__dirname + '/同源策略.html');
    });
    app.get('/data', (request, response) => {
        //響應資料
        response.send('服務端返回的資料');
    });
    
  • 客戶端html:

        const btn = document.getElementsByTagName('button')[0];
        btn.onclick = function () {
            //console.log('測試');
            //傳送ajax請求
            const xhr = new XMLHttpRequest();
            xhr.open('GET', '/data');//同源請求,路徑可以簡寫
            xhr.send();
            xhr.onreadystatechange = function () {
               if(xhr.readyState === 4){
                   if(xhr.status >= 200 && xhr.status < 300){
                       console.log(xhr.response);
                   }
               }
            }
        }
    



二、解決跨域(JSONP、CORS)

1、非官方解決途徑JSONP:

(1) JSONP 是什麼?

JSONP(JSON with Padding),是一個非官方的跨域解決方案,只支援 get 請求

(2) JSONP 怎麼工作的?

在網頁有一些標籤天生具有跨域能力,比如:img link iframe script。 JSONP 就是利用 script 標籤

利用script的路徑src作為請求路徑,然後只需要服務端返回的資料封裝成js程式碼即可

■ jsonp例子1:

  • 服務端處理,響應返回js程式碼(跟我們平時引入外部的js程式碼一樣啦):
app.get('/jsonp', (request, response) => {
    //響應資料
    response.send('console.log("hello jsonp")');
});
  • 客戶端處理:
<script src="http://127.0.0.1:9000/jsonp"></script>

■ jsonp例子2(驗證使用者名稱,顯示密碼):

  • 服務端處理:

    //服務端驗證使用者名稱
    app.all('/check', (request, response) => {
        //響應資料
        // response.send('console.log("hello jsonp")');
        const data = {
            name:'admin',
            password:'123456'
        };
        let str = JSON.stringify(data);
        response.end(`handle(${str})`);//呼叫客戶端(前端)的handle方法
    });
    
  • 客戶端處理:

      使用者名稱: <input type="text" name="name"/>
      <p></p>
    
      <script>
        const input = document.getElementsByTagName('input')[0];
        const p = document.querySelector('p');
    
        //宣告一個handle函式,用來給服務端呼叫,以處理服務端返回的資料
        function handle(data) {
            input.style.border = "solid 1px #f00";
            let username = input.value;
            //若使用者名稱正確,將服務端返回的資料顯示到p標籤內
            if(username === data.name){
                p.innerHTML = data.password;
            }
        }
    
        input.onblur = function () {
            //向服務端傳送請求(jsonp),檢查使用者是否存在
            const script = document.createElement('script');
            //設定script標籤的src為ajax的url
            script.src = 'http://127.0.0.1:9000/check';
            //在介面生成dom元素
            document.body.appendChild(script);
        }
    </script>
    
    

學習AJAX必知必會(5)~同源策略、解決跨域問題(JSONP、CORS)



❀ jsop跨域訪問第三方介面,請求成功,但是卻拿不到資料?

從上面的例子可以看到當服務端是第三方(例如訪問百度的快遞介面:https://express.baidu.com/express/api/express),
通過jsonp跨域方式去訪問第三方介面,結果:請求成功,狀態碼是200,但是無法拿到響應的資料.


  • 原因1:第三方服務在建立路由規則時,設定不允許跨域訪問,所以提示CORB,無法直接拿到資料;
  • 原因2:想通過script標籤的 src='請求url' 引入服務端響應回來的js程式碼,但是且不知道第三方服務端響應時是怎麼書寫的,不知道回撥了什麼函式
  • 總結:jsonp 解決跨域訪問,除了型別是GET,還需要伺服器的配合才能完成跨域

□ 我們自己的服務端沒設定允許跨域訪問,預設為不允許跨域訪問
□ 但是我們在服務端設定請求時響應回去一些js程式碼(handle函式的呼叫(data的json物件作為引數)的js程式碼
□ 在客戶端我們通過 src='請求url' 引入服務端響應回來的js程式碼,而我們知道我們服務端響應回來一個handle函式的呼叫,所以我們在客戶端定義了一個handle回撥函式(handle函式的引數是響應回來的json格式的資料)。



2、官方解決途徑CORS:

(1)CORS: Cross-Origin Resource Sharing 跨域資源共享, 即服務端設定響應頭是允許跨域的

(2)CORS的更多介紹:跨源資源共享(CORS) - HTTP | MDN (mozilla.org)

  • 服務端cors跨域請求處理:

    app.all('/cors', (request, response) => {
        //設定響應頭(允許跨域)
        response.setHeader('Access-Control-Allow-Origin', '*');
        // response.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:9000);
    
        //設定響應頭(允許自定義請求頭)
        response.setHeader('Access-Control-Allow-Headers', '*');
        //設定響應頭(允許自定義請求方式)
        response.setHeader('Access-Control-Allow-Method', '*');
    
        //設定響應體
        response.send('hello cors');
    });
    
  • 客戶端處理:

    <button>點選傳送ajax請求</button>
    
    <script>
        const btn = document.getElementsByTagName('button')[0];
        btn.onclick = function () {
            const xhr = new XMLHttpRequest();
            xhr.open('get', 'http://127.0.0.1:9000/cors');
            xhr.send();
            xhr.onreadystatechange = function () {
                if(xhr.readyState === 4){
                    if(xhr.status >= 200 && xhr.status < 300){
                        console.log(xhr.response);
                    }
                }
            }
        }
    </script>
    

相關文章