最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

JavaScript解決跨域的三種方法小結(jié)

 更新時(shí)間:2024年03月14日 09:03:13   作者:好好吃飯e  
在Web應(yīng)用中,當(dāng)一個(gè)網(wǎng)頁的腳本試圖去請(qǐng)求另一個(gè)域名下的資源時(shí),就會(huì)遇到跨域問題,跨域問題是由瀏覽器的同源策略所引起的,本文給大家介紹了JavaScript解決跨域的三種方法,需要的朋友可以參考下

前言

什么是跨域問題

在Web應(yīng)用中,當(dāng)一個(gè)網(wǎng)頁的腳本試圖去請(qǐng)求另一個(gè)域名下的資源時(shí),就會(huì)遇到跨域問題??缬騿栴}是由瀏覽器的同源策略所引起的。換句話說:后端返回給瀏覽器的數(shù)據(jù)會(huì)被瀏覽器的同源策略給攔截下來。

同源策略要求資源的協(xié)議、域名和端口號(hào)都必須相同,才能確保數(shù)據(jù)的安全性。如果不滿足這個(gè)條件,請(qǐng)求將被瀏覽器拒絕,從而導(dǎo)致跨域問題的出現(xiàn)。

  • 同源策略: 協(xié)議號(hào)-域名-端口號(hào) 都相同的地址,瀏覽器才認(rèn)為是同源
協(xié)議號(hào):域名:端口號(hào) / 路徑

https://192.168.31.45:8080/user

https://192.168.31.45:8080/list

上面這個(gè)例子雖然它們的路徑不一樣但是協(xié)議號(hào)、域名、端口號(hào)都相同,所以它們就是同源的

跨域問題的原因

跨域問題主要是由于瀏覽器的安全策略限制引起的。同源策略的目的是保護(hù)用戶的隱私和數(shù)據(jù)安全,防止惡意網(wǎng)站獲取用戶的敏感信息或進(jìn)行未授權(quán)的操作。 通過限制跨域請(qǐng)求,瀏覽器有效地減少了許多網(wǎng)絡(luò)攻擊的風(fēng)險(xiǎn),例如跨站腳本攻擊(XSS)和跨站請(qǐng)求偽造(CSRF)。

JSONP

JSONP(JSON with Padding)是一種用于解決跨域請(qǐng)求的技術(shù),它利用了 <script> 標(biāo)簽可以跨域加載資源的特性。

下面是 JSONP 解決跨域請(qǐng)求的基本原理:

  • 前端發(fā)起 JSONP 請(qǐng)求: 前端頁面通過動(dòng)態(tài)創(chuàng)建 <script> 標(biāo)簽,設(shè)置其 src 屬性為包含回調(diào)函數(shù)的 URL。通常這個(gè) URL 是指向另一個(gè)域名下的服務(wù)器接口。
  • 服務(wù)端返回?cái)?shù)據(jù): 服務(wù)端接收到 JSONP 請(qǐng)求后,會(huì)將數(shù)據(jù)包裝在回調(diào)函數(shù)中返回給前端。這樣前端頁面就可以獲得跨域請(qǐng)求返回的數(shù)據(jù)。
  • 前端處理數(shù)據(jù): 前端頁面定義好與回調(diào)函數(shù)同名的 JavaScript 函數(shù),當(dāng)服務(wù)端返回?cái)?shù)據(jù)時(shí),會(huì)執(zhí)行這個(gè)函數(shù)并傳入返回的數(shù)據(jù)作為參數(shù),從而實(shí)現(xiàn)跨域數(shù)據(jù)的獲取和處理。

前端代碼:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <button id="btn">獲取數(shù)據(jù)</button>
  <script>
    // 定義一個(gè)函數(shù) jsonp,用于發(fā)送 JSONP 請(qǐng)求
    function jsonp(url, cb) {
      return new Promise((resolve, reject) => {
        // 創(chuàng)建一個(gè) script 標(biāo)簽
        const script = document.createElement('script');
        
        // 設(shè)置 script 的 src 屬性,包含了請(qǐng)求的 URL 和回調(diào)函數(shù)名稱
        script.src = `${url}?cb=${cb}`; // http://localhost:3000?cb='callback'
        
        // 將 script 添加到文檔中
        document.body.appendChild(script); // 瀏覽器自動(dòng)請(qǐng)求 src 中的內(nèi)容
        
        // 定義一個(gè)全局函數(shù),用于處理返回的數(shù)據(jù)
        window[cb] = (data) => {
          resolve(data)
        }
      })
    }
    
    // 獲取按鈕元素
    let btn = document.getElementById('btn');
    
    // 綁定點(diǎn)擊事件
    btn.addEventListener('click', () => {
      // 發(fā)送 JSONP 請(qǐng)求
      jsonp('http://localhost:3000', 'callback')
      .then(res => {
        console.log('后端的返回結(jié)果:' + res);
      })

    })
  </script>
</body>
</html>

后端代碼:

const Koa = require('koa');
const app = new Koa();

// 定義中間件函數(shù) main,處理請(qǐng)求并返回?cái)?shù)據(jù)
const main = (ctx, next) => {
  console.log(ctx.query); // 輸出請(qǐng)求參數(shù)對(duì)象 { cb: 'callback' }
  
  // 從請(qǐng)求參數(shù)中獲取回調(diào)函數(shù)名稱
  const cb = ctx.query.cb;

  // 準(zhǔn)備要返回給前端的數(shù)據(jù)
  const data = '給前端的數(shù)據(jù)';
  
  // 構(gòu)造帶有回調(diào)函數(shù)名稱的字符串,格式為 'callback("給前端的數(shù)據(jù)")'
  const str = `${cb}('${data}')`;
  
  // 將構(gòu)造好的字符串作為響應(yīng)體返回給前端
  ctx.body = str;
}

// 將 main 中間件注冊(cè)到 Koa 應(yīng)用中
app.use(main);

// 監(jiān)聽 3000 端口,啟動(dòng)服務(wù)器
app.listen(3000, () => {
  console.log('listening on port 3000');
})

優(yōu)點(diǎn):

  • 簡(jiǎn)單易用: JSONP 實(shí)現(xiàn)簡(jiǎn)單,只需在前端添加一個(gè) <script> 標(biāo)簽即可完成跨域請(qǐng)求,無需復(fù)雜的配置。
  • 兼容性好: JSONP 能夠兼容各種瀏覽器,包括早期版本的瀏覽器,因?yàn)樗峭ㄟ^動(dòng)態(tài)創(chuàng)建 <script> 標(biāo)簽實(shí)現(xiàn)的。
  • 支持跨域請(qǐng)求: JSONP 可以在不同域之間進(jìn)行數(shù)據(jù)通信,解決了傳統(tǒng) AJAX 請(qǐng)求受同源策略限制的問題。

缺點(diǎn):

  • 安全性問題: JSONP 存在安全風(fēng)險(xiǎn),因?yàn)樗峭ㄟ^在前端動(dòng)態(tài)加載腳本來獲取數(shù)據(jù),可能會(huì)被用于注入惡意腳本,導(dǎo)致安全漏洞。
  • 只支持 GET 請(qǐng)求: JSONP 只能發(fā)起 GET 請(qǐng)求,無法支持其他類型的 HTTP 請(qǐng)求,如 POST、PUT 等。
  • 依賴服務(wù)端支持: JSONP 需要服務(wù)端返回?cái)?shù)據(jù)時(shí)將其包裹在一個(gè)回調(diào)函數(shù)中,因此需要服務(wù)端提供支持,如果服務(wù)端不支持 JSONP 格式返回?cái)?shù)據(jù),則無法使用該方法。

CORS(跨域資源共享)

CORS是一種機(jī)制,允許服務(wù)器在響應(yīng)中攜帶一個(gè)特殊的標(biāo)頭,以告知瀏覽器該服務(wù)器允許哪些源的網(wǎng)頁訪問其資源。 可以總結(jié)為一句話:后端通過設(shè)置響應(yīng)頭來告訴瀏覽器不要拒絕接受后端的響應(yīng)。

前端代碼:在用戶點(diǎn)擊按鈕時(shí),通過發(fā)送跨域請(qǐng)求獲取服務(wù)器返回的數(shù)據(jù),并將數(shù)據(jù)打印到瀏覽器的控制臺(tái)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <button id="btn">獲取數(shù)據(jù)</button>

  <script>
    let btn = document.getElementById('btn');
    btn.addEventListener('click', () => {
      fetch('http://localhost:3000')  // 發(fā)送跨域請(qǐng)求到服務(wù)器
      .then(res => res.json())
      .then((res) => {
        console.log(res);  // 打印返回的數(shù)據(jù)到控制臺(tái)
      })
    })

  </script>
</body>
</html>

代碼實(shí)現(xiàn)了以下功能:

  • 在 HTML 中定義了一個(gè)按鈕元素,id 為 "btn",用于觸發(fā)發(fā)送數(shù)據(jù)請(qǐng)求。
  • 在 JavaScript 部分,使用 fetch 函數(shù)發(fā)送 GET 請(qǐng)求到指定的服務(wù)器地址 "http://localhost:3000"。
  • 在成功接收到服務(wù)器響應(yīng)后,使用 .then 方法將響應(yīng)解析為 JSON 格式。
  • 在第二個(gè) .then 方法中,處理解析后的數(shù)據(jù),并將其輸出到瀏覽器的控制臺(tái)。

后端代碼 :Node.js 服務(wù)器代碼,創(chuàng)建了一個(gè) HTTP 服務(wù)器,監(jiān)聽在端口 3000。當(dāng)接收到請(qǐng)求時(shí),返回一個(gè)包含 "hello cors" 消息的 JSON 數(shù)據(jù)。

const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200, {
     // cros實(shí)現(xiàn)原理
    'Access-Control-Allow-Origin': 'http://127.0.0.1:5500'  // 允許來自指定地址的跨域請(qǐng)求
  })

  let data = {
    msg: "hello cors"
  }
  res.end(JSON.stringify(data)) // 返回?cái)?shù)據(jù)給前端頁面
})

server.listen(3000, () => {
  console.log('listening on port 3000');
})

后端代碼第6行在服務(wù)端設(shè)置響應(yīng)頭來控制跨域訪問。

常見的響應(yīng)頭包括:

  • Access-Control-Allow-Origin:指定允許訪問的域名。

  • 例如,Access-Control-Allow-Origin: *表示允許所有域名訪問,

  • Access-Control-Allow-Origin:'http://127.0.0.1:5500'表示只允許特定域名訪問。

  • Access-Control-Allow-Methods:指定允許的HTTP方法。

  • Access-Control-Allow-Headers:指定允許的自定義請(qǐng)求頭。

CORS支持各種類型的HTTP請(qǐng)求,包括GET、POST等。

domain

我們還可以使用 Domain 方法來解決一些特定情況下的跨域訪問問題。 在跨域通信時(shí),還需要注意以下幾點(diǎn):

  • 頁面的域名必須滿足 Domain 方法的限制,即二級(jí)域名相同(如 example.com)。

  • 父級(jí)頁面需要在設(shè)置 document.domain 之前定義需要共享的變量或?qū)ο蟆?/p>

  • 子級(jí)頁面可以通過 window.parent 來訪問父級(jí)頁面的屬性或變量,但需要確保父級(jí)頁面已經(jīng)加載完成并且兩者的域名設(shè)置已生效。

下面舉一個(gè)簡(jiǎn)單的例子來說明 Domain 方法的用法:

假設(shè)有兩個(gè)頁面分別位于不同子域名下,一個(gè)是 parent.example.com,另一個(gè)是 child.example.com。我們希望這兩個(gè)頁面能夠進(jìn)行跨域通信。

在父級(jí)頁面 parent.example.com/index.html 中的代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Parent Page</title>
</head>
<body>
  <h1>Parent Page</h1>
  <iframe src="http://child.example.com/child.html"></iframe>
  
  <script>
    document.domain = 'example.com';
    var messageFromParent = 'Hello from parent page!';
  </script>
</body>
</html>

在子級(jí)頁面 child.example.com/child.html 中的代碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Child Page</title>
</head>
<body>
  <h1>Child Page</h1>
  
  <script>
    document.domain = 'example.com';
    var messageFromChild = 'Hello from child page!';
    
    // 訪問父級(jí)頁面定義的變量
    var message = window.parent.messageFromParent;
    console.log('Message from parent: ' + message);
  </script>
</body>
</html>

在這個(gè)例子中,父級(jí)頁面和子級(jí)頁面分別設(shè)置了相同的 document.domain 為 'example.com',以實(shí)現(xiàn)二級(jí)域名相同。

父級(jí)頁面定義了一個(gè)名為 messageFromParent 的變量,子級(jí)頁面在加載后通過 window.parent 來訪問父級(jí)頁面定義的變量,并打印出父級(jí)頁面的消息。

通過設(shè)置相同的 document.domain,父子頁面之間就可以進(jìn)行跨域通信,實(shí)現(xiàn)數(shù)據(jù)共享和交互。

postMessage

使用 postMessage() 方法結(jié)合 <iframe> 元素可以實(shí)現(xiàn)跨域通信,這是一種常見的技術(shù)。通過在父窗口和嵌套的 <iframe> 之間使用 postMessage() 方法,可以安全地在不同源之間進(jìn)行通信。

<iframe> 可以用于解決跨域通信的問題,其原理是利用瀏覽器中同源策略的限制,將不同域的內(nèi)容加載到獨(dú)立的 <iframe> 中,通過 postMessage 方法進(jìn)行跨文檔通信。

在 a.html 文件中:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h2>a.html</h2>

  <!-- 創(chuàng)建一個(gè) iframe 元素來加載 b.html -->
  <iframe src="http://127.0.0.1:5500/postMessage/b.html" frameborder="0" id="iframe"></iframe>

  <script>
    // 向 b.html 發(fā)送數(shù)據(jù)
    let iframe = document.getElementById('iframe');
    iframe.onload = function() {
      // 準(zhǔn)備要發(fā)送的數(shù)據(jù)
      let data = {
        name: 'Tom'
      };
      // 通過 postMessage 方法向 iframe 發(fā)送數(shù)據(jù)
      iframe.contentWindow.postMessage(JSON.stringify(data), 'http://127.0.0.1:5500');
    }

    // 監(jiān)聽來自 b.html 的消息
    window.addEventListener('message', function(e) {
      console.log(e.data);
    });
  </script>
</body>
</html>

在 b.html 文件中:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <h4>b.html</h4>

  <script>
    // 監(jiān)聽來自父頁面的消息
    window.addEventListener('message', function(e) {
      console.log(JSON.parse(e.data));

      if (e.data) {
        // 收到消息后延遲 2 秒發(fā)送回應(yīng)給父頁面
        setTimeout(function() {
          window.parent.postMessage('我接受到', 'http://127.0.0.1:5500');
        }, 2000);
      }
    });
  </script>
</body>
</html>

優(yōu)點(diǎn):

  • 安全性:  使用 <iframe> 結(jié)合 postMessage 進(jìn)行跨域通信是一種相對(duì)安全的方法,能夠避免常見的跨站腳本攻擊(XSS)。
  • 靈活性:  可以在不同域之間傳遞數(shù)據(jù),實(shí)現(xiàn)更豐富的交互體驗(yàn),如單點(diǎn)登錄、共享數(shù)據(jù)等。
  • 適用性廣泛:  跨域通信是 Web 開發(fā)中常見需求,而 <iframe> 結(jié)合 postMessage 是一種通用且有效的解決方案。

缺點(diǎn):

  • 復(fù)雜性:  跨域通信涉及到多個(gè)文檔之間的交互,需要額外的處理和編碼,增加了開發(fā)的復(fù)雜度。
  • 性能開銷:  使用 <iframe> 進(jìn)行跨域通信可能會(huì)引入額外的網(wǎng)絡(luò)請(qǐng)求和資源加載,對(duì)頁面加載性能有一定影響。
  • 兼容性:  舊版本的瀏覽器可能對(duì) postMessage 支持不完整,需要做兼容性處理。

以上就是JavaScript解決跨域的三種方法的詳細(xì)內(nèi)容,更多關(guān)于JavaScript解決跨域的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

加查县| 平定县| 崇文区| 上杭县| 蚌埠市| 仁布县| 乐清市| 湟中县| 尤溪县| 凉山| 射洪县| 珲春市| 广灵县| 万安县| 周口市| 榆林市| 城市| 石楼县| 凌海市| 霍林郭勒市| 马边| 杭锦旗| 翁牛特旗| 漳州市| 永吉县| 墨竹工卡县| 乡城县| 凤阳县| 馆陶县| 神木县| 平江县| 昌图县| 岫岩| 石阡县| 迁安市| 铜梁县| 平南县| 绍兴县| 左贡县| 镇赉县| 高淳县|