JavaScript筆記之跨域

在了解跨域之前,我們先了解下什么是同源策略

1.什么是同源策略?

同源策略/SOP(Same origin policy)是一種約定,由Netscape公司1995年引入瀏覽器,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,瀏覽器很容易受到XSS、CSFR等攻擊。所謂同源是指"協(xié)議+域名+端口"三者相同,即便兩個不同的域名指向同一個ip地址,也非同源。

同源

不同源

需要注意的是: 對于當(dāng)前頁面來說頁面存放的 JS 文件的域不重要,重要的是加載該 JS 頁面所在什么域

2.什么是跨域?

瀏覽器從一個域名的網(wǎng)頁去請求另一個域名的資源時,域名、端口、協(xié)議任一不同,都是跨域

3.跨域的幾種解決方式

  1. 使用JSONP方式實(shí)現(xiàn)跨域
    原理:JSONP是通過script標(biāo)簽加載數(shù)據(jù)的方式去獲取數(shù)據(jù)當(dāng)做JS代碼來執(zhí)行。具體操作方法:提前在頁面上聲明一個函數(shù)(這個函數(shù)用來處理后端返回的數(shù)據(jù)),函數(shù)名通過接口的方式傳遞給后臺;后臺解析到函數(shù)名后在原始數(shù)據(jù)上[包裹]這個函數(shù)名(即相當(dāng)于將后臺返回來的數(shù)據(jù)作為函數(shù)的參數(shù),執(zhí)行該函數(shù)),發(fā)送給前端。換句話說,JSONP 需要對應(yīng)接口的后端的配合才能實(shí)現(xiàn)。
      1. 定義數(shù)據(jù)處理函數(shù)_fun
      2. 創(chuàng)建script標(biāo)簽,src的地址執(zhí)行后端接口,最后加個參數(shù)  callback=_fun
      3. 服務(wù)端在收到請求后,解析參數(shù),計(jì)算返還數(shù)據(jù),輸出 fun(data) 字符串。
      4. fun(data)會放到script標(biāo)簽做為js執(zhí)行。此時會調(diào)用fun函數(shù),將data做為參數(shù)。
    
  2. CORS
    CORS 全稱是跨域資源共享(Cross-Origin Resource Sharing),是一種 ajax 跨域請求資源的方式,支持現(xiàn)代瀏覽器,IE支持10以上。
    實(shí)現(xiàn)方式:當(dāng)你使用 XMLHttpRequest 發(fā)送請求時,瀏覽器發(fā)現(xiàn)該請求不符合同源策略,會給該請求加一個請求頭:Origin,后臺進(jìn)行一系列處理,如果確定接受請求則在返回結(jié)果中加入一個響應(yīng)頭:Access-Control-Allow-Origin; 瀏覽器判斷該相應(yīng)頭中是否包含 Origin 的值,如果有則瀏覽器會處理響應(yīng),我們就可以拿到響應(yīng)數(shù)據(jù),如果不包含瀏覽器直接駁回,這時我們無法拿到響應(yīng)數(shù)據(jù)。所以 CORS 的表象是讓你覺得它與同源的 ajax 請求沒啥區(qū)別,代碼完全一樣。
  3. 降域
    此方案僅限主域相同,子域不同的跨域應(yīng)用場景。
    實(shí)現(xiàn)原理:兩個頁面都通過js強(qiáng)制設(shè)置document.domain為基礎(chǔ)主域,就實(shí)現(xiàn)了同域。
       <script>
            document.domain = 'xxx.com'
       </script>
    
  4. postMessage
    window.postMessage() 方法可以安全地實(shí)現(xiàn)跨源通信
    從廣義上講,一個窗口可以獲得對另一個窗口的引用(比如 targetWindow = window.opener),然后在窗口上調(diào)用 targetWindow.postMessage() 方法分發(fā)一個 MessageEvent, MessageEvent 是接口代表一段被目標(biāo)對象接收的消息。")消息。接收消息的窗口可以根據(jù)需要自由處理此事件。傳遞給 window.postMessage() 的參數(shù)(比如 message )將通過消息事件對象暴露給接收消息的窗口
  • 用法:postMessage(data,origin,[transfer])方法接受兩個參數(shù),第三個參數(shù)可選。
  • data: html5規(guī)范支持任意基本類型或可復(fù)制的對象
  • origin: 協(xié)議+主機(jī)+端口號,也可以設(shè)置為*,表示可以傳遞給任意窗口,如果要指定和當(dāng)前窗口同源的話設(shè)置為/
    <div class="ct">
    <h1>使用postMessage實(shí)現(xiàn)跨域</h1>
    <div class="main">
        <input type="text" placeholder="http://a.jrg.com:8080/a.html">
    </div>
    <iframe src="http://localhost:8080/b.html" frameborder="0" ></iframe>
    </div>
     //a.html里的js代碼
    <script>
      $('.main input').addEventListener('input', function(){
            console.log(this.value);
            window.frames[0].postMessage(this.value,'*');//向b.html傳送跨域數(shù)據(jù)
    
        })
      // 接收b.html返回回來的數(shù)據(jù)
      window.addEventListener('message',function(e) {
              $('.main input').value = e.data  
                console.log(e.data);
      });
    </script>
    //b.html里的js代碼
    <script>
    //接收a.html的數(shù)據(jù)
    window.addEventListener('message',function(e) {
        $('#input').value = e.data
            console.log(e.data);
    });   
    //返回?cái)?shù)據(jù)給a.html
     $('#input').addEventListener('input', function(){
      window.parent.postMessage(this.value, '*');
    })
    </script>
    

4. CORS具體的實(shí)現(xiàn)代碼

  • 使用XMLHttpRequest發(fā)送請求,瀏覽器發(fā)現(xiàn)該請求不符合同源策略,會給該請求加一個請求頭:Origin;后臺進(jìn)行處理,在返回結(jié)果中加入一個響應(yīng)頭:Access-Control-Allow-Origin;瀏覽器判斷該相應(yīng)頭中是否包含 Origin的值,有則處理響應(yīng),無則直接駁回
  • res.setHeader('Access-Control-Allow-Origin','127.0.0.1:8080')
  • res.setHeader('Access-Control-Allow-Origin','*')
  • index.html頁面
      <!DOCTYPE html>
      <html lang="en">
      <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
      </head>
      <body>
        <div class="container">
          <ul class="news"></ul>
          <button class="show">show news</button>
        </div>
    
        <script>
          function $(selector){
            return document.querySelector(selector)
          }
          function appendHtml(news){
            var html = ''
            for (var i=0; i<news.length; i++){
              html += '<li>'+ news[i] + '</li>'
            }
            $('.news').innerHTML = html
          }
          $('.show').addEventListener('click', function(){
            var xhr = new XMLHttpRequest()
            xhr.open('GET', 'http://127.0.0.1:8080/getNews', true)
            
            xhr.onload = function(){
              appendHtml(JSON.parse(xhr.responseText))
            }
            xhr.send()
          })
        </script>
      </body>
      </html>
    
  • server.js
    var http = require('http')
    var fs = require('fs')
    var path = require('path')
    var url = require('url')
    
    http.createServer(function(req,res){
      var pathObj = url.parse(req.url,true)
      switch (pathObj.pathname){
        case '/getNews':
          var news = [
            "這是第一條消息,獲取了消息一",
            "這是第二條消息,獲取了消息二",
            "這是第三條消息,獲取了消息三"
          ]
          res.setHeader('Access-Control-Allow-Origin','127.0.0.1:8080')
          res.end(JSON.stringify(news))
          break;
        
          default:
            fs.readFile(path.join(__dirname,pathObj.pathname),function(e,data){
              if(e){
                res.writeHead(404,'not found')
                res.end('<h1>404 Not Found</h1>')
              } else {
                res.end(data)
              }
            })
          } 
      }).listen(8080)
    
  • 啟動終端,執(zhí)行 node server.js
    啟動服務(wù)器.PNG
  • 瀏覽器打開http://localhost:8080/index.html ,查看效果和網(wǎng)絡(luò)請求
    localhost.PNG
  • 點(diǎn)擊[show news]按鈕 ,會出現(xiàn)下圖報(bào)錯,因?yàn)楹蠖嗽O(shè)置的Access-Control-Allow-Origin127.0.0.1:8080
    wrong1.PNG
  • 瀏覽器打開http://127.0.0.1:8080/index.html ,點(diǎn)擊[show news]按鈕 ,此時網(wǎng)頁能正常響應(yīng)
    ok1.PNG
  • 若將 res.setHeader('Access-Control-Allow-Origin','127.0.0.1:8080')
    改成 res.setHeader('Access-Control-Allow-Origin','*'),打開服務(wù)器,瀏覽器打開http://localhost:8080/index.html,瀏覽器頁能正常響應(yīng)。*表示匹配所有的窗口
    ok2.PNG

以上為簡單為跨域簡單總結(jié)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 什么是跨域 跨域,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript實(shí)...
    Yaoxue9閱讀 1,413評論 0 6
  • 什么是跨域 跨域,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript實(shí)...
    他方l閱讀 1,140評論 0 2
  • 什么是跨域 跨域,是指瀏覽器不能執(zhí)行其他網(wǎng)站的腳本。它是由瀏覽器的同源策略造成的,是瀏覽器對JavaScript實(shí)...
    HeroXin閱讀 956評論 0 4
  • 題目1: 什么是同源策略 瀏覽器出于安全考慮,只允許與本域下的接口交互。不同源的客戶端腳本在沒有明確授權(quán)的情況下,...
    saintkl閱讀 277評論 0 0
  • Source調(diào)試JS代碼 理解單步調(diào)試,單步進(jìn)入塊,單步退出塊的區(qū)別 單步調(diào)試F10 跳過當(dāng)前函數(shù)調(diào)用 單步進(jìn)入塊...
    pepsi1000閱讀 720評論 0 0

友情鏈接更多精彩內(nèi)容