跨域的幾種方案

因為瀏覽器出于安全考慮,有同源策略。也就是說,如果協議、域名、端口有一個不同就是跨域,Ajax 請求會失敗。

我們可以通過以下幾種常用方法解決跨域的問題

JSONP

JSONP 的原理很簡單,就是利用 <script> 標簽沒有跨域限制的漏洞。通過 <script> 標簽指向一個需要訪問的地址并提供一個回調函數來接收數據

涉及到的端

JSONP 需要服務端和前端配合實現。

<script src="http://domain/api?param1=a&param2=b&callback=jsonp"></script>
<script>function jsonp(data) {console.log(data)}
</script>    

JSONP 使用簡單且兼容性不錯,但是只限于 get 請求

具體實現方式

在開發中可能會遇到多個 JSONP 請求的回調函數名是相同的,這時候就需要自己封裝一個 JSONP,以下是簡單實現

function jsonp(url, jsonpCallback, success) {let script = document.createElement("script");script.src = url;script.async = true;script.type = "text/javascript";window[jsonpCallback] = function(data) {success && success(data);};document.body.appendChild(script);
}
jsonp("http://xxx","callback",function(value) {console.log(value);}
);

CORS

CORS (Cross-Origin Resource Sharing,跨域資源共享) 是目前最為廣泛的解決跨域問題的方案。方案依賴服務端/后端在響應頭中添加 Access-Control-Allow-* 頭,告知瀏覽器端通過此請求

涉及到的端

CORS 只需要服務端/后端支持即可,不涉及前端改動

  • CORS需要瀏覽器和后端同時支持。IE 8 和 9 需要通過 XDomainRequest 來實現。
  • 瀏覽器會自動進行 CORS 通信,實現CORS通信的關鍵是后端。只要后端實現了 CORS,就實現了跨域。
  • 服務端設置 Access-Control-Allow-Origin 就可以開啟 CORS。 該屬性表示哪些域名可以訪問資源,如果設置通配符則表示所有網站都可以訪問資源。

CORS 實現起來非常方便,只需要增加一些 HTTP 頭,讓服務器能聲明允許的訪問來源

只要后端實現了 CORS,就實現了跨域

image.png

以 koa框架舉例

添加中間件,直接設置Access-Control-Allow-Origin請求頭

app.use(async (ctx, next)=> {ctx.set('Access-Control-Allow-Origin', '*');ctx.set('Access-Control-Allow-Headers', 'Content-Type, Content-Length, Authorization, Accept, X-Requested-With , yourHeaderFeild');ctx.set('Access-Control-Allow-Methods', 'PUT, POST, GET, DELETE, OPTIONS');if (ctx.method == 'OPTIONS') {ctx.body = 200; } else {await next();}
})

具體實現方式

CORS 將請求分為簡單請求(Simple Requests)和需預檢請求(Preflighted requests),不同場景有不同的行為

簡單請求:不會觸發預檢請求的稱為簡單請求。當請求滿足以下條件時就是一個簡單請求:

  • 請求方法:GET、HEAD、POST。
  • 請求頭:Accept、Accept-Language、Content-Language、Content-Type。
    • Content-Type 僅支持:application/x-www-form-urlencoded、multipart/form-data、text/plain

需預檢請求:當一個請求不滿足以上簡單請求的條件時,瀏覽器會自動向服務端發送一個 OPTIONS 請求,通過服務端返回的Access-Control-Allow-* 判定請求是否被允許

CORS 引入了以下幾個以 Access-Control-Allow-* 開頭:

  • Access-Control-Allow-Origin 表示允許的來源
  • Access-Control-Allow-Methods 表示允許的請求方法
  • Access-Control-Allow-Headers 表示允許的請求頭
  • Access-Control-Allow-Credentials 表示允許攜帶認證信息

當請求符合響應頭的這些條件時,瀏覽器才會發送并響應正式的請求

nginx反向代理

反向代理只需要服務端/后端支持,幾乎不涉及前端改動,只用切換接口即可

nginx 配置跨域,可以為全局配置和單個代理配置(兩者不能同時配置)

全局配置,在nginx.conf文件中的 http 節點加入跨域信息

http {# 跨域配置add_header 'Access-Control-Allow-Origin' '$http_origin' ;add_header 'Access-Control-Allow-Credentials' 'true' ;add_header 'Access-Control-Allow-Methods' 'PUT,POST,GET,DELETE,OPTIONS' ;add_header 'Access-Control-Allow-Headers' 'Content-Type,Content-Length,Authorization,Accept,X-Requested-With' ;
}

局部配置(單個代理配置跨域), 在路徑匹配符中加入跨域信息

server {listen       8080;server_name  server_name;charset utf-8;location / {# 這里配置單個代理跨域,跨域配置add_header 'Access-Control-Allow-Origin' '$http_origin' ;add_header 'Access-Control-Allow-Credentials' 'true' ;add_header 'Access-Control-Allow-Methods' 'PUT,POST,GET,DELETE,OPTIONS' ;add_header 'Access-Control-Allow-Headers' 'Content-Type,Content-Length,Authorization,Accept,X-Requested-With' ;#配置代理 代理到本機服務端口proxy_pass http://127.0.0.1:9000;proxy_redirect   off;proxy_set_header Host $host:$server_port;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;}
}

Node 中間層接口轉發

const router = require('koa-router')()
const rp = require('request-promise');// 通過node中間層轉發實現接口跨域
router.post('/github', async (ctx, next) => {let {category = 'trending',lang = 'javascript',limit,offset,period} = ctx.request.body lang = lang || 'javascript'limit = limit || 30offset = offset || 0period = period || 'week'let res =  await rp({method: 'POST',// 跨域的接口uri: `https://e.juejin.cn/resources/github`,body: {category,lang,limit,offset,period},json: true})ctx.body = res
})module.exports = router

Proxy

如果是通過vue-cli腳手架工具搭建項目,我們可以通過webpack為我們起一個本地服務器作為請求的代理對象

通過該服務器轉發請求至目標服務器,得到結果再轉發給前端,但是最終發布上線時如果web應用和接口服務器不在一起仍會跨域

在vue.config.js文件,新增以下代碼

module.exports = {devServer: {host: '127.0.0.1',port: 8080,open: true,// vue項目啟動時自動打開瀏覽器proxy: {'/api': { // '/api'是代理標識,用于告訴node,url前面是/api的就是使用代理的target: "http://xxx.xxx.xx.xx:8080", //目標地址,一般是指后臺服務器地址changeOrigin: true, //是否跨域pathRewrite: { // pathRewrite 的作用是把實際Request Url中的'/api'用""代替'^/api': "" }}}}
}

通過axios發送請求中,配置請求的根路徑

axios.defaults.baseURL = '/api'

此外,還可通過服務端實現代理請求轉發,以express框架為例

var express = require('express');
const proxy = require('http-proxy-middleware')
const app = express()
app.use(express.static(__dirname + '/'))
app.use('/api', proxy({ target: 'http://localhost:4000', changeOrigin: false}));
module.exports = app

websocket

webSocket本身不存在跨域問題,所以我們可以利用webSocket來進行非同源之間的通信

原理:利用webSocket的API,可以直接new一個socket實例,然后通過open方法內send要傳輸到后臺的值,也可以利用message方法接收后臺傳來的數據。后臺是通過new WebSocket.Server({port:3000})實例,利用message接收數據,利用send向客戶端發送數據。具體看以下代碼:

function socketConnect(url) {// 客戶端與服務器進行連接let ws = new WebSocket(url); // 返回`WebSocket`對象,賦值給變量ws// 連接成功回調ws.onopen = e => {console.log('連接成功', e)ws.send('我發送消息給服務端'); // 客戶端與服務器端通信}// 監聽服務器端返回的信息ws.onmessage = e => {console.log('服務器端返回:', e.data)// do something}return ws; // 返回websocket對象
}
let wsValue = socketConnect('ws://121.40.165.18:8800'); // websocket對象

document.domain(不常用)

  • 該方式只能用于二級域名相同的情況下,比如 a.test.com 和 b.test.com 適用于該方式。
  • 只需要給頁面添加 document.domain = ‘test.com’ 表示二級域名都相同就可以實現跨域
  • 自 Chrome 101 版本開始,document.domain 將變為可讀屬性,也就是意味著上述這種跨域的方式被禁用了

postMessage(不常用)

在兩個 origin 下分別部署一套頁面 A 與 B,A 頁面通過 iframe 加載 B 頁面并監聽消息,B 頁面發送消息

這種方式通常用于獲取嵌入頁面中的第三方頁面數據。一個頁面發送消息,另一個頁面判斷來源并接收消息

// 發送消息端
window.parent.postMessage('message', 'http://test.com');
// 接收消息端
var mc = new MessageChannel();
mc.addEventListener('message', (event) => {var origin = event.origin || event.originalEvent.origin;if (origin === 'http://test.com') {console.log('驗證通過')}
});

window.name(不常用)

主要是利用 window.name 頁面跳轉不改變的特性實現跨域,即 iframe 加載一個跨域頁面,設置 window.name,跳轉到同域頁面,可以通過 $(‘iframe’).contentWindow.name 拿到跨域頁面的數據

實例說明

比如有一個www.example.com/a.html頁面。需要通過a.html頁面里的js來獲取另一個位于不同域上的頁面www.test.com/data.html中的數據。

data.html頁面中設置一個window.name即可,代碼如下

<script>window.name = "我是data.html中設置的a頁面想要的數據";
</script>
  • 那么接下來問題來了,我們怎么把data.html頁面載入進來呢,顯然我們不能直接在a.html頁面中通過改變window.location來載入data.html頁面(因為我們現在需要實現的是a.html頁面不跳轉,但是也能夠獲取到data.html中的數據)
  • 具體的實現其實就是在a.html頁面中使用一個隱藏的iframe來充當一個中間角色,由iframe去獲取data.html的數據,然后a.html再去得到iframe獲取到的數據。
  • 充當中間人的iframe想要獲取到data.html中通過window.name設置的數據,只要要把這個iframe的src設置為www.test.com/data.html即可,然后a.html想要得到iframe所獲取到的數據,也就是想要得到iframe的widnow.name的值,還必須把這個iframe的src設置成跟a.html頁面同一個域才行,不然根據同源策略,a.html是不能訪問到iframe中的window.name屬性的
<!-- a.html中的代碼 -->
<iframe id="proxy" src="http://www.test.com/data.html" style="display: none;" onload = "getData()"> <script>function getData(){var iframe = document.getElementById('proxy);iframe.onload = function(){var data = iframe.contentWindow.name;//上述即為獲取iframe里的window.name也就是data.html頁面中所設置的數據;}iframe.src = 'b.html'; //這里的b為隨便的一個頁面,只有與a.html同源就行,目的讓a.html等訪問到iframe里的東西,設置成about:blank也行}
</script>

上面的代碼只是最簡單的原理演示代碼,你可以對使用js封裝上面的過程,比如動態的創建iframe,動態的注冊各種事件等等,當然為了安全,獲取完數據后,還可以銷毀作為代理的iframe

補充

跨域與監控

前端項目在統計前端報錯監控時會遇到上報的內容只有 Script Error 的問題。這個問題也是由同源策略引起。在 <script> 標簽上添加 crossorigin=“anonymous” 并且返回的 JS 文件響應頭加上 Access-Control-Allow-Origin: * 即可捕捉到完整的錯誤堆棧

跨域與圖片

前端項目在圖片處理時可能會遇到圖片繪制到 Canvas 上之后卻不能讀取像素或導出 base64 的問題。這個問題也是由同源策略引起。解決方式和上文相同,給圖片添加 crossorigin=“anonymous” 并在返回的圖片文件響應頭加上 Access-Control-Allow-Origin: * 即可解決

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/80849.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/80849.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/80849.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于EFISH-SCB-RK3576/SAIL-RK3576的智能安檢機技術方案?

&#xff08;國產化替代J1900的全場景技術解析&#xff09; 一、硬件架構設計? ?核心處理模塊? ?異構計算架構?&#xff1a; ?四核Cortex-A72&#xff08;2.3GHz&#xff09;?&#xff1a;運行X光圖像重建算法&#xff08;FDK反投影&#xff09;&#xff0c;支持雙能譜…

MQ防重復消費----去重表結合 Spring AOP 切面編程,抽象封裝成通用冪等注解

以下內容包含針對 NoMQDuplicateConsumeAspect 的深度面試問答、消息隊列重投遞觸發場景、AOP 切面編程擴展&#xff0c;以及基于已有實現的關鍵要點與步驟總結。文中所有論斷均引用多源資料&#xff0c;以助于您在面試與實戰中全面展示對冪等消費切面及消息重投的理解。 一、深…

[:, :, 1]和[:, :, 0] 的區別; `prompt_vector` 和 `embedding_matrix`的作用

prompt_vector = torch.sum(prompt_embedding * attention_weights.unsqueeze(-1), dim=1) # [1, hidden_dim] prompt_vector = torch.sum(prompt_embedding * attention_weights.unsqueeze(-1), dim=1) 主要作用是通過將 prompt_embedding 與 attention_weights 相乘后再按指…

Dinky 安裝部署并配置提交 Flink Yarn 任務

官方文檔 https://www.dinky.org.cn/docs/1.1/deploy_guide/normal_deploy 版本 dinky 1.1.0、1.2.3 當前最新發布版本為 1.2.3 &#xff0c;但是官方文檔最新穩定版為 1.1 &#xff0c;所以先選擇 1.1.0&#xff0c;驗證通過后&#xff0c;再嘗試 1.2.3 &#xff0c;發現 1…

java連數據庫

一、準備工作 ??安裝MySQL數據庫?? 確保已安裝MySQL服務器并啟動服務 ??下載JDBC驅動?? 官方驅動&#xff1a;MySQL Connector/JMaven依賴&#xff1a; <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactI…

【生態信息】開源軟件全方位解析

開源軟件(0pen Source Software&#xff0c;0ss)是指其源代碼可以公開發布、查看、使用和修改的軟件。這一概念的核心在于開放性和共享性&#xff0c;允許開發者自由地使用、修改、分發以及改進軟件。開源軟件通常遵循特定的開源許可證&#xff0c;這些許可證確保了軟件的自由使…

探秘 DeerFlow:字節跳動開源的科研創作魔法盒!

1.前言 字節跳動于2025年5月9日開源了名為DeerFlow的全新Deep Research項目&#xff0c;該項目基于LangStack框架&#xff0c;旨在通過人工智能技術簡化科研和內容創作流程。DeerFlow整合了語言模型、網絡搜索、爬蟲和Python代碼執行等多種工具&#xff0c;支持深度研究、MCP集…

機器學習第十一講:標準化 → 把厘米和公斤單位統一成標準值

機器學習第十一講&#xff1a;標準化 → 把厘米和公斤單位統一成標準值 資料取自《零基礎學機器學習》。 查看總目錄&#xff1a;學習大綱 關于DeepSeek本地部署指南可以看下我之前寫的文章&#xff1a;DeepSeek R1本地與線上滿血版部署&#xff1a;超詳細手把手指南 一、買菜…

less中使用 @supports

在Less中使用supports supports 是CSS的條件規則&#xff0c;用于檢測瀏覽器是否支持特定的CSS屬性或值。在Less中&#xff0c;你可以像在普通CSS中一樣使用supports&#xff0c;同時還能利用Less的特性來增強它。 基本用法 /* 檢測瀏覽器是否支持display: flex */ supports …

LeetCode Hot100 (1/100)

目錄 一、有關數組和動態數組的排序&#xff08;sort函數&#xff09; 1.普通數組的排序 基本用法 降序排序 2.vector的排序 基本用法 降序排序 二、數組長度和一些vector的基本語法 1. 靜態數組長度計算? 2. 安全獲取數組長度&#xff08;C17 起&#xff09;? 3.vecto…

通過MCP讓LLM調用系統接口

場景 MCP的出現大大豐富了LLM的功能&#xff0c;對于存量系統&#xff0c;我們希望能讓模型調用已有的接口&#xff0c;以最小的成本讓AI能夠獲取系統內部數據。因此我們開發了一個名為http-api-call的MCP Server&#xff0c;來支持模型到內部API的調用 實現方案 使用用標準…

基于Transformer的多資產收益預測模型實戰(附PyTorch實現與避坑指南)

基于Transformer的多資產收益預測模型實戰(附PyTorch模型訓練及可視化完整代碼) 一、項目背景與目標 在量化投資領域,利用時間序列數據預測資產收益是核心任務之一。傳統方法如LSTM難以捕捉資產間的復雜依賴關系,而Transformer架構通過自注意力機制能有效建模多資產間的聯…

養生:打造健康生活的全方位策略

在生活節奏不斷加快的當下&#xff0c;養生已成為提升生活質量、維護身心平衡的重要方式。從飲食、運動到睡眠&#xff0c;再到心態調節&#xff0c;各個方面的養生之道共同構建起健康生活的堅實基礎。以下為您詳細介紹養生的關鍵要點&#xff0c;助您擁抱健康生活。 飲食養生…

輕型汽車鼓式液壓制動器系統設計

一、設計基礎參數 1.1 整車匹配參數 參數項數值范圍整備質量1200-1500kg最大設計車速160km/h輪胎規格195/65 R15制動法規要求GB 12676-2014 1.2 制動性能指標 制動減速度&#xff1a;≥6.2m/s&#xff08;0型試驗&#xff09; 熱衰退率&#xff1a;≤30%&#xff08;連續10…

無法更新Google Chrome的解決問題

解決問題&#xff1a;原文鏈接&#xff1a;【百分百成功】Window 10 Google Chrome無法啟動更新檢查&#xff08;錯誤代碼為1&#xff1a;0x80004005&#xff09; google谷歌chrome瀏覽器無法更新Chrome無法更新至最新版本&#xff1f; 下載了 就是更新Google Chrome了

【AAAI 2025】 Local Conditional Controlling for Text-to-Image Diffusion Models

Local Conditional Controlling for Text-to-Image Diffusion Models&#xff08;文本到圖像擴散模型的局部條件控制&#xff09; 文章目錄 內容摘要關鍵詞作者及研究團隊項目主頁01 研究領域待解決問題02 論文解決的核心問題03 關鍵解決方案04 主要貢獻05 相關研究工作06 解決…

Kuka AI音樂AI音樂開發「人聲伴奏分離」 —— 「Kuka Api系列|中文咬字清晰|AI音樂API」第6篇

導讀 今天我們來了解一下 Kuka API 的人聲與伴奏分離功能。 所謂“人聲伴奏分離”&#xff0c;顧名思義&#xff0c;就是將一段完整的音頻拆分為兩個獨立的軌道&#xff1a;一個是人聲部分&#xff0c;另一個是伴奏&#xff08;樂器&#xff09;部分。 這個功能在音樂創作和…

Idea 設置編碼UTF-8 Idea中 .properties 配置文件中文亂碼

Idea 設置編碼UTF-8 Idea中 .properties 配置文件中文亂碼 一、設置編碼 1、步驟&#xff1a; File -> Setting -> Editor -> File encodings --> 設置編碼二、配置文件中文亂碼 1、步驟&#xff1a; File -> Setting -> Editor -> File encodings ->…

Xilinx FPGA PCIe | XDMA IP 核 / 應用 / 測試 / 實踐

注&#xff1a;本文為 “Xilinx FPGA 中 PCIe 技術與 XDMA IP 核的應用” 相關文章合輯。 圖片清晰度受引文原圖所限。 略作重排&#xff0c;未整理去重。 如有內容異常&#xff0c;請看原文。 FPGA&#xff08;基于 Xilinx&#xff09;中 PCIe 介紹以及 IP 核 XDMA 的使用 N…

sqli—labs第六關——雙引號報錯注入

一&#xff1a;判斷輸入類型 首先測試 ?id1&#xff0c;?id1&#xff0c;?id1"&#xff0c;頁面回顯均無變化 所以我們采用簡單的布爾測試&#xff0c;分別測試數字型&#xff0c;單引號&#xff0c;雙引號 然后發現&#xff0c;只有在測試到雙引號注入的時候符合關鍵…