自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

跨域是個(gè)什么鬼,你搞明白了嗎?

網(wǎng)絡(luò) 通信技術(shù)
跨域是個(gè)老生常談的話題了,最近不管在和后端聯(lián)調(diào),或者搞微前端的時(shí)候都會(huì)遇到,正好寫篇文章來總結(jié)一下吧。

[[433686]]

跨域是個(gè)老生常談的話題了,最近不管在和后端聯(lián)調(diào),或者搞微前端的時(shí)候都會(huì)遇到,正好寫篇文章來總結(jié)一下吧。

跨域是什么

這里的“跨域”指的是不同源之間的資源訪問。只要請(qǐng)求的 url 有以下不同,都屬于“跨域”:

  • 協(xié)議: http, https, ...
  • 域名
  • 端口

有人可能會(huì)覺得,我自己網(wǎng)站肯定只訪問自己服務(wù)器,肯定都是部署在一個(gè)域名的呀。

但是有的時(shí)候,一個(gè)網(wǎng)頁可能要對(duì)接后端多個(gè)服務(wù):一會(huì)對(duì)接支付,一會(huì)對(duì)接用戶信息。每個(gè)組的后端可能都會(huì)有自己的域名。在這樣的場(chǎng)景下,跨域就非常常見了。

為什么會(huì)有跨域

我們常說的“跨域”問題,其實(shí)是在說“跨域”訪問的限制問題,相信大家對(duì)下面的報(bào)錯(cuò)習(xí)以為常了:

這種“跨域”限制其實(shí)是 瀏覽器自帶的安全機(jī)制,只有 在瀏覽器上 發(fā)生跨域請(qǐng)求操作時(shí),瀏覽器就會(huì)自動(dòng)拋出上面的錯(cuò)誤。

注意,這僅在瀏覽器上會(huì)出現(xiàn)這樣的限制,如果你用 Postman 這些工具訪問 url 是沒有“跨域”限制的,畢竟 Postman 連域名這些玩意都沒有,哪來的“跨域”。

CORS

雖然瀏覽器出于安全考慮做了“跨域”訪問的限制,但開發(fā)時(shí)不可避免會(huì)有這樣不同源資源訪問的需求,因此 W3C 就制定了 CORS(Cross-origin resource sharing 跨域資源共享) 的機(jī)制。

很多人一直以為 CORS = 跨域,其實(shí) CORS 是一種解決“跨域”的方案。

需要注意的是,CORS 是一個(gè)“新”的協(xié)議(至少對(duì)于以前的 IE7 是新的),不僅需要瀏覽器支持,也后端服務(wù)器的支持。

瀏覽器支持沒什么好說的,就是瀏覽器版本是否支持的問題:

然后就是后端服務(wù)器支持了,服務(wù)器需要在 Response Header 上添加 Access-Control-xxx-yyy 的字段,瀏覽器識(shí)別到了,才能放行該請(qǐng)求。比如,最常見的就是加 Access-Control-Allow-Origin 這個(gè)返回頭,值設(shè)置為需要放行的域名。

簡(jiǎn)單請(qǐng)求 VS 非簡(jiǎn)單請(qǐng)求

瀏覽器將 CORS 請(qǐng)求分為 簡(jiǎn)單請(qǐng)求 和 非簡(jiǎn)單請(qǐng)求。

簡(jiǎn)單請(qǐng)求 會(huì)在發(fā)送時(shí)自動(dòng)在 HTTP 請(qǐng)求頭加上 Origin 字段,來標(biāo)明當(dāng)前是哪個(gè)源(協(xié)議+域名+端口),服務(wù)端來決定是否放行。

非簡(jiǎn)單請(qǐng)求 則會(huì)先發(fā)一個(gè) OPTIONS 預(yù)檢請(qǐng)求給服務(wù)端,當(dāng)通過了再發(fā)正常的 CORS 請(qǐng)求。

對(duì)于 簡(jiǎn)單請(qǐng)求,請(qǐng)求方法為以下三種之一:

  • Head
  • Post
  • Get

且 HTTP 請(qǐng)求頭字段不能超過以下字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type

同時(shí) Content-Type 只能三個(gè)值:

  • application/x-www-form-urlencoded 對(duì)應(yīng)普通表單
  • multipart/form-data 對(duì)應(yīng)文件上傳
  • text/plain 對(duì)應(yīng)文本發(fā)送(一般不怎么用)

只要不滿足上面條件的,都屬于 非簡(jiǎn)單請(qǐng)求。

可能很多人會(huì)自然地覺得 POST 請(qǐng)求都是 非簡(jiǎn)單請(qǐng)求,因?yàn)槲覀兂?吹桨l(fā) POST 時(shí),都會(huì)先發(fā) OPTIONS。其實(shí)是因?yàn)槲覀円话愣紩?huì)傳 JSON 格式的數(shù)據(jù),Content-Type 為 application/json,所以,這樣的 POST 請(qǐng)求才屬于 非簡(jiǎn)單請(qǐng)求。

Access-Control-xxx-yyyy

當(dāng) CORS 請(qǐng)求為 簡(jiǎn)單請(qǐng)求時(shí),請(qǐng)求會(huì)檢測(cè)返回頭里的以下字段:

  • Access-Control-Allow-Origin:指定哪些源是可以共享資源的(包含協(xié)議、域名、端口)。
  • Access-Control-Allow-Credentials:當(dāng)請(qǐng)求需要攜帶 Cookie 時(shí),需要加上這個(gè)字段為 true 才能允許攜帶 Cookie。
  • Access-Control-Expose-Headers:由于 XMLHttpRequest 對(duì)象只能拿到 Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma 這 6 個(gè)基本字段。想要在拿到別的字段,就需要在這里去指定。

而當(dāng) CORS 請(qǐng)求為 非簡(jiǎn)單請(qǐng)求時(shí),瀏覽器會(huì)先發(fā)一個(gè) OPTIONS 預(yù)檢(preflight)請(qǐng)求,這個(gè)請(qǐng)求會(huì)檢查如下字段:

  • Access-Control-Request-Method:指定可訪問的方法,對(duì)于非簡(jiǎn)單請(qǐng)求,可能會(huì)用到 PUT,PATCH,DELETE 等 RESTful 方法,服務(wù)端需要把這些方法名也加上。
  • Access-Control-Request-Headers:指定 HTTP 請(qǐng)求頭會(huì)額外添加的信息。一個(gè)很常見的場(chǎng)景就是,后端有時(shí)候會(huì)將一些環(huán)境參數(shù)放到請(qǐng)求頭里,如果不用這個(gè)字段來指定放行的字段,那么就會(huì)出現(xiàn)“跨域”限制了。

如果 OPTIONS 請(qǐng)求沒有通過服務(wù)端的校驗(yàn),就會(huì)返回一個(gè)正常的 HTTP 請(qǐng)求,不會(huì)帶上 CORS 的返回信息,所以瀏覽器就會(huì)認(rèn)定為“跨域”了。

總結(jié)一句話就是,當(dāng) Console 報(bào)哪個(gè)錯(cuò),你就在服務(wù)端返回頭上加上哪個(gè)字段就可以了。

CORS 中間件

無論對(duì)于 Express 還是 KOA,我們都不需要再手動(dòng)添加上面的字段了,直接加一個(gè) cors 中間件就可以很方便地添加上面的字段,寫起來也更優(yōu)雅:

  1. var cors = require('cors'); 
  2.  
  3. var corsOptions = { 
  4.   origin: function (origin, callback) { 
  5.     // db.loadOrigins is an example call to load 
  6.     // a list of origins from a backing database 
  7.     db.loadOrigins(function (error, origins) { 
  8.       callback(error, origins) 
  9.     }) 
  10.   } 
  11.  
  12. app.use('/', cors(corsOptions), indexRouter); 

JSONP

那對(duì)于瀏覽器不支持 CORS 的情況呢?雖然目前來看是不太可能,但是在還沒有 CORS 的時(shí)代,大家是怎么解決跨域的呢?答案就是 JSONP。

它的原理也非常簡(jiǎn)單:雖然瀏覽器限制了 HTTP 的跨域,但是沒有限制獲取 script 標(biāo)簽內(nèi)容的跨域請(qǐng)求呀。

 

當(dāng)我們插入一個(gè) <script src="xxx.com"> 標(biāo)簽的時(shí)候,會(huì)發(fā)一個(gè)獲取 xxx.com 的 GET 請(qǐng)求,而這個(gè) GET 請(qǐng)求又不存在“跨域”限制,通過這樣的方法就能解決跨域的問題了。

服務(wù)端實(shí)現(xiàn):

  1. router.get('/', (req, res) =>  { 
  2.   const { callback_name } = req.query; 
  3.   res.send(`${callback_name}('hello')`) // 返回 JS 代碼,調(diào)用 callback_name 這個(gè)函數(shù),并傳入 hello 
  4. }); 

前端實(shí)現(xiàn):

  1. function jsonpCallback(params) { 
  2.   alert('執(zhí)行 public/index.html 里定義的 jsonpCallback 函數(shù),并傳入' + params + '參數(shù)'); 
  3.  
  4.  
  5. const jsonp = async () => { 
  6.   // 制作 script 標(biāo)簽 
  7.   const script = document.createElement('script'); 
  8.   script.type = 'text/javascript'
  9.   script.src = 'http://localhost:9000/user?callback_name=jsonpCallback' 
  10.   // 添加標(biāo)簽 
  11.   document.body.appendChild(script); 
  12.   // 拿到數(shù)據(jù)再移除 
  13.   document.body.removeChild(script); 
  14.  
  15. jsonp(); 

當(dāng)調(diào)用 jsonp 函數(shù)的時(shí)候,自動(dòng)創(chuàng)建一個(gè) script 標(biāo)簽,再把請(qǐng)求放到 scr 里,就會(huì)自動(dòng)發(fā)起 GET 請(qǐng)求。服務(wù)端會(huì)直接返回一串 JavaScript 代碼,然后前端執(zhí)行這段從服務(wù)端獲取來的 JS 代碼,獲取到后端數(shù)據(jù)。

跨域場(chǎng)景

“跨域”不僅存在于接口訪問,還會(huì)有以下場(chǎng)景:

  • 前端訪問跨域 URL,最常見的場(chǎng)景,需要后端添加 cors 的返回字段
  • 微前端:主應(yīng)用和子應(yīng)用之間的資源訪問可能存在“跨域”操作,需要子應(yīng)用/主應(yīng)用添加 cors
  • 登錄重定向:本質(zhì)上和第一條一樣,不過在現(xiàn)象層面不太一樣。比如訪問 abc.com 時(shí),有的網(wǎng)站會(huì)重定向到自己的登錄頁 passport.abc.com,如果 passport.abc.com 沒有設(shè)置 cors,也會(huì)出現(xiàn)跨域

總結(jié)

總的來說,我們常說的“跨域”,其實(shí)就是獲取不同源(協(xié)議+域名+端口)的資源時(shí),瀏覽器自身 做出的限制。

在以前,開發(fā)者會(huì)用 JSONP 這種通過生成一個(gè) script 標(biāo)簽,自動(dòng)發(fā)起 GET 請(qǐng)求的方式來解決跨域,但是這種方式非常不安全,不推薦。

到了現(xiàn)在,瀏覽器都已經(jīng)完美支持 CORS 機(jī)制了,只需要在服務(wù)端添加對(duì)應(yīng)的返回頭 Access-Control-xxx-yyy 就可以了。當(dāng)瀏覽器報(bào)“跨域”錯(cuò)誤時(shí),缺哪個(gè)字段,就在服務(wù)端配哪個(gè)字段即可。

Node 端開發(fā)時(shí),我們可以直接使用 cors 中間件來配置,就不用手寫返回頭里的字段了。

 

責(zé)任編輯:武曉燕 來源: 寫代碼的海怪
相關(guān)推薦

2022-12-30 08:35:00

2024-05-30 08:19:52

微服務(wù)架構(gòu)大型應(yīng)用

2022-05-04 08:38:32

Netty網(wǎng)絡(luò)框架

2015-05-21 15:45:13

2023-08-26 21:42:08

零拷貝I/O操作

2015-09-18 09:17:06

數(shù)據(jù)分析

2023-07-27 08:26:36

零拷貝I/O操作

2017-06-14 11:18:40

2022-09-27 07:31:57

Property模式數(shù)據(jù)

2022-10-10 18:38:56

inert屬性鍵盤

2023-12-08 08:38:15

EventLoopAPI瀏覽器

2022-04-07 11:15:22

PulseEventAPI函數(shù)

2023-12-28 08:43:28

前端算法搜索

2024-01-08 20:05:32

2022-10-19 08:19:32

動(dòng)態(tài)基線預(yù)警

2018-04-03 14:49:24

2025-01-15 00:00:00

存儲(chǔ)整數(shù)集Roaring

2022-10-08 00:24:40

嵌套事務(wù)加入事務(wù)事務(wù)

2023-12-11 08:03:01

Java線程線程組

2022-10-31 10:03:03

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)