• 自動秒收錄
  • 軟件:1973
  • 資訊:57811|
  • 收錄網站:279872|

IT精英團

前端面試必須解決網絡中的跨域問題

前端面試必須解決網絡中的跨域問題

瀏覽次數:
評論次數:
編輯: 樂詠
信息來源: ITPUB
更新日期: 2022-05-20 21:39:29
摘要

什么是跨域瀏覽器有一個重要的安全策略,稱之為「同源策略」其中,源=協議+主機+端口源=協議+主機+端口源=協議+主機+端口,兩個源相同,稱之為同源,兩個源不同,稱之為跨源或跨域比如:源1源2是否同

  • 正文開始
  • 相關閱讀
  • 推薦作品

什么是跨域

瀏覽器有一個重要的安全策略,稱為“同源策略”

其中源=協議主機端口源=協議主機端口源=協議主機端口,兩個源相同,稱之為同源,兩個源不同,稱之為跨源或跨域

例如:

來源1

來源2

同源?

www.baidu.com[1]

www.baidu.com/news[2]

www.baidu.com[3]

www.baidu.com[4]

http://本地主機:5000

http://localhost:7000

http://localhost:5000

http://127.0.0.1:5000[8]

www.baidu.com[9]

百度網[10]

同源策略是指,若頁面的源和頁面運行過程中加載的源不一致時,出于安全考慮,瀏覽器會對跨域的資源訪問進行一些限制

Image-20210916104747296同源策略是對ajax跨域最嚴厲的限制。默認情況下,它不允許ajax訪問跨域資源。

Image-20210916105741041因此,我們通常所說的跨域問題就是同源策略對ajax的影響。

解決跨域問題的方法有很多。常見的有:

代理,常用

CORS,常用

JSONP

不管是哪種方式,都要讓瀏覽器知道我的跨域請求是自己人的,不要攔截。

跨域解決方法1-代理

對于前端開發而言,大多數跨領域的問題都是通過代理來解決的。

代理適用的場景是:生產環境不發生跨域,但開發環境發生跨域

因此,只需要使用代理來解決開發環境中的跨域問題,也稱為開發代理。

tps://image.z.itpub.net/zitpub.net/JPG/2022-05-20/AF8F5F72A8ADC6FA92976B4ED4C70BBB.jpg" width="1302" src="https://image.z.itpub.net/zitpub.net/JPG/2022-05-20/AF8F5F72A8ADC6FA92976B4ED4C70BBB.jpg">
image-20210916125008693

在實際開發中,只需要對開發服務器稍加配置即可完成

// vue 的開發服務器代理配置
// vue.config.js
module.exports = {
  devServer: { // 配置開發服務器
    proxy: { // 配置代理
      "/api": { // 若請求路徑以 /api 開頭
        target: "http://dev.taobao.com", // 將其轉發到 http://dev.taobao.com
      },
    },
  },
};
復制代碼

跨域解決方法2-JSONP

在CORS出現之前,人們想了一種奇妙的辦法來實現跨域,這就是JSONP。

要實現JSONP,需要瀏覽器和服務器來一個天衣無縫的絕妙配合。

JSONP的做法是:當需要跨域請求時,不使用AJAX,轉而生成一個script元素去請求服務器,由于瀏覽器并不阻止script元素的請求,這樣請求可以到達服務器。服務器拿到請求后,響應一段JS代碼,這段代碼實際上是一個函數調用,調用的是客戶端預先生成好的函數,并把瀏覽器需要的數據作為參數傳遞到函數中,從而間接的把數據傳遞給客戶端

image-20210916151516184

JSONP有著明顯的缺點,即其只能支持GET請求

跨域解決方法3-CORS

概述

CORS是基于http1.1的一種跨域解決方案,它的全稱是Cross-Origin Resource Sharing,跨域資源共享。

它的總體思路是:如果瀏覽器要跨域訪問服務器的資源,需要獲得服務器的允許

image-20200421152122793

而要知道,一個請求可以附帶很多信息,從而會對服務器造成不同程度的影響

比如有的請求只是獲取一些新聞,有的請求會改動服務器的數據

針對不同的請求,CORS 規定了三種不同的交互模式,分別是:

  • 簡單請求
  • 需要預檢的請求
  • 附帶身份憑證的請求

這三種模式從上到下層層遞進,請求可以做的事越來越多,要求也越來越嚴格。

下面分別說明三種請求模式的具體規范。

簡單請求

當瀏覽器端運行了一段 ajax 代碼(無論是使用 XMLHttpRequest 還是 fetch api),瀏覽器會首先判斷它屬于哪一種請求模式

簡單請求的判定

當請求同時滿足以下條件時,瀏覽器會認為它是一個簡單請求:

  1. 請求方法屬于下面的一種:
  • get
  • post
  • head
  • 請求頭僅包含安全的字段,常見的安全字段如下:
    • Accept
    • Accept-Language
    • Content-Language
    • Content-Type
    • DPR
    • Downlink
    • Save-Data
    • Viewport-Width
    • Width
  • 請求頭如果包含Content-Type,僅限下面的值之一:
    • text/plain
    • multipart/form-data
    • application/x-www-form-urlencoded

    如果以上三個條件同時滿足,瀏覽器判定為簡單請求。

    下面是一些例子:

    // 簡單請求
    fetch('http://crossdomain.com/api/news');

    // 請求方法不滿足要求,不是簡單請求
    fetch('http://crossdomain.com/api/news', {
      method: 'PUT',
    });

    // 加入了額外的請求頭,不是簡單請求
    fetch('http://crossdomain.com/api/news', {
      headers: {
        a: 1,
      },
    });

    // 簡單請求
    fetch('http://crossdomain.com/api/news', {
      method: 'post',
    });

    // content-type不滿足要求,不是簡單請求
    fetch('http://crossdomain.com/api/news', {
      method: 'post',
      headers: {
        'content-type': 'application/json',
      },
    });
    復制代碼

    簡單請求的交互規范

    當瀏覽器判定某個ajax 跨域請求簡單請求時,會發生以下的事情

    1. 請求頭中會自動添加Origin字段

    比如,在頁面http://my.com/index.html中有以下代碼造成了跨域

    // 簡單請求
    fetch('http://crossdomain.com/api/news');
    復制代碼

    請求發出后,請求頭會是下面的格式:

    GET /api/news/ HTTP/1.1
    Host: crossdomain.com
    Connection: keep-alive
    ...
    Referer: http://my.com/index.html
    Origin: http://my.com
    復制代碼

    看到最后一行沒,Origin字段會告訴服務器,是哪個源地址在跨域請求

    1. 服務器響應頭中應包含Access-Control-Allow-Origin

    當服務器收到請求后,如果允許該請求跨域訪問,需要在響應頭中添加Access-Control-Allow-Origin字段

    該字段的值可以是:

    • *:表示我很開放,什么人我都允許訪問
    • 具體的源:比如http://my.com,表示我就允許你訪問

    實際上,這兩個值對于客戶端http://my.com而言,都一樣,因為客戶端才不會管其他源服務器允不允許,就關心自己是否被允許

    當然,服務器也可以維護一個可被允許的源列表,如果請求的Origin命中該列表,才響應*或具體的源

    為了避免后續的麻煩,強烈推薦響應具體的源

    假設服務器做出了以下的響應:

    HTTP/1.1 200 OK
    Date: Tue, 21 Apr 2020 08:03:35 GMT
    ...
    Access-Control-Allow-Origin: http://my.com
    ...

    消息體中的數據
    復制代碼

    當瀏覽器看到服務器允許自己訪問后,高興的像一個兩百斤的孩子,于是,它就把響應順利的交給 js,以完成后續的操作

    下圖簡述了整個交互過程

    image-20200421162846480

    需要預檢的請求

    簡單的請求對服務器的威脅不大,所以允許使用上述的簡單交互即可完成。

    但是,如果瀏覽器不認為這是一種簡單請求,就會按照下面的流程進行:

    1. 瀏覽器發送預檢請求,詢問服務器是否允許
    2. 服務器允許
    3. 瀏覽器發送真實請求
    4. 服務器完成真實的響應

    比如,在頁面http://my.com/index.html中有以下代碼造成了跨域

    // 需要預檢的請求
    fetch('http://crossdomain.com/api/user', {
      method: 'POST', // post 請求
      headers: {
        // 設置請求頭
        a: 1,
        b: 2,
        'content-type': 'application/json',
      },
      body: JSON.stringify({ name: '袁小進', age: 18 }), // 設置請求體
    });
    復制代碼

    瀏覽器發現它不是一個簡單請求,則會按照下面的流程與服務器交互

    1. **瀏覽器發送預檢請求,詢問服務器是否允許**
    OPTIONS /api/user HTTP/1.1
    Host: crossdomain.com
    ...
    Origin: http://my.com
    Access-Control-Request-Method: POST
    Access-Control-Request-Headers: a, b, content-type
    復制代碼

    可以看出,這并非我們想要發出的真實請求,請求中不包含我們的請求頭,也沒有消息體。

    這是一個預檢請求,它的目的是詢問服務器,是否允許后續的真實請求。

    預檢請求沒有請求體,它包含了后續真實請求要做的事情

    預檢請求有以下特征:

    • 請求方法為OPTIONS
    • 沒有請求體
    • 請求頭中包含
      • Origin:請求的源,和簡單請求的含義一致
      • Access-Control-Request-Method:后續的真實請求將使用的請求方法
      • Access-Control-Request-Headers:后續的真實請求會改動的請求頭
    1. 服務器允許

    服務器收到預檢請求后,可以檢查預檢請求中包含的信息,如果允許這樣的請求,需要響應下面的消息格式

    HTTP/1.1 200 OK
    Date: Tue, 21 Apr 2020 08:03:35 GMT
    ...
    Access-Control-Allow-Origin: http://my.com
    Access-Control-Allow-Methods: POST
    Access-Control-Allow-Headers: a, b, content-type
    Access-Control-Max-Age: 86400
    ...
    復制代碼

    對于預檢請求,不需要響應任何的消息體,只需要在響應頭中添加:

    • Access-Control-Allow-Origin:和簡單請求一樣,表示允許的源
    • Access-Control-Allow-Methods:表示允許的后續真實的請求方法
    • Access-Control-Allow-Headers:表示允許改動的請求頭
    • Access-Control-Max-Age:告訴瀏覽器,多少秒內,對于同樣的請求源、方法、頭,都不需要再發送預檢請求了
    1. 瀏覽器發送真實請求

    預檢被服務器允許后,瀏覽器就會發送真實請求了,上面的代碼會發生下面的請求數據

    POST /api/user HTTP/1.1
    Host: crossdomain.com
    Connection: keep-alive
    ...
    Referer: http://my.com/index.html
    Origin: http://my.com

    {"name": "xiaoming", "age": 18 }
    復制代碼
    1. **服務器響應真實請求**
    HTTP/1.1 200 OK
    Date: Tue, 21 Apr 2020 08:03:35 GMT
    ...
    Access-Control-Allow-Origin: http://my.com
    ...

    添加用戶成功
    復制代碼

    可以看出,當完成預檢之后,后續的處理與簡單請求相同

    下圖簡述了整個交互過程

    image-20200421165913320

    附帶身份憑證的請求

    默認情況下,ajax 的跨域請求并不會附帶 cookie,這樣一來,某些需要權限的操作就無法進行

    不過可以通過簡單的配置就可以實現附帶 cookie

    // xhr
    var xhr = new XMLHttpRequest();
    xhr.withCredentials = true;

    // fetch api
    fetch(url, {
      credentials: 'include',
    });
    復制代碼

    這樣一來,該跨域的 ajax 請求就是一個_附帶身份憑證的請求_

    當一個請求需要附帶 cookie 時,無論它是簡單請求,還是預檢請求,都會在請求頭中添加cookie字段

    而服務器響應時,需要明確告知客戶端:服務器允許這樣的憑據

    告知的方式也非常的簡單,只需要在響應頭中添加:Access-Control-Allow-Credentials: true即可

    對于一個附帶身份憑證的請求,若服務器沒有明確告知,瀏覽器仍然視為跨域被拒絕。

    另外要特別注意的是:**對于附帶身份憑證的請求,服務器不得設置 Access-Control-Allow-Origin 的值為***。這就是為什么不推薦使用*的原因

    一個額外的補充

    在跨域訪問時,JS 只能拿到一些最基本的響應頭,如:Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma,如果要訪問其他頭,則需要服務器設置本響應頭。

    Access-Control-Expose-Headers頭讓服務器把允許瀏覽器訪問的頭放入白名單,例如:

    Access-Control-Expose-Headers: authorization, a, b
    復制代碼

    這樣 JS 就能夠訪問指定的響應頭了。


    關于本文

    如何在Bash腳本中使用強大的Linux測試命令
    ? 上一篇 2022-05-20
    胡迪核心知識點詳解(好文章合集)
    下一篇 ? 2022-05-20
    • 如何在Ubuntu中保留文件系統并備份當前開發板鏡像
      0閱讀 0條評論 個贊
      在Ubuntu保留文件系統或者說備份當前開發板鏡像的需求在不斷增加。比如Ubuntu文件系統需要安裝庫文件的話直接使用apt-get工具就可以下載,但由于需要下載的核心板較多,比較費時間,這時需要將安……
    • 國產核心板全志T507助力消防系統升級
      0閱讀 0條評論 個贊
      9月16日下午,位于湖南長沙市區內的中國電信大樓發生火災,建筑高度218米,現場濃煙滾滾,數十層樓體燃燒劇烈。消防救援人員趕到現場后很快將火勢控制住,目前大樓火勢已被撲滅,所幸未發現人員傷亡。湖南電信……
    • 教大家如何處理Spring Boot易流中的用戶和群體!
      0閱讀 0條評論 個贊
      1.準備工作2.用戶操作2.1添加用戶2.2修改用戶2.3刪除用戶2.4查詢用戶3.組操作3.1添加組3.2修改組3.3刪除組3.4查詢組4.查看表詳情雖然說我們在實際開發中,……
    • 從PG15開始WAL壓縮優化
      0閱讀 0條評論 個贊
      PG15傳聞中的超級令人激動的功能大多數跳票了,年初我也寫過一個關于PG15新功能跳票的文章。PG15BETA已經發出幾個月了,似乎PG15里令人激動人心的功能不多,不過從長長的新功能列表里,……
    • 深入了解美團葉子發射器開源方案
      0閱讀 0條評論 個贊
      大家好,我是樹哥。之前我們有聊過「如何設計一個分布式ID發號器」,其中有講過4種解決方案,分別是:UUID類雪花算法數據庫自增主鍵Redis原子自增美團以第2、3種解決方案為基礎,開發出……
    發表評論 共有條評論
    用戶名: 密碼:
    驗證碼: 匿名發表
    • MQ系列5:5的發送模式:RocketMQ消息
      0閱讀 0條評論 個贊
      在之前的篇章中,我們學習了RocketMQ的原理,以及RocketMQ中命名服務ServiceName的運行流程,本篇從消息的生產、消費來理解一條消息的生命周期。1消息生產在RocketMQ中……
    • i.MX8MQ自制背板無PCIe問題詳解
      9閱讀 0條評論 個贊
      在飛凌嵌入式OKMX8MQ-C開發板上有兩個PCIe接口,對應著兩個PCIe差分時鐘,兩路PCIe分別用作了M.2接口卡槽KEYE(P37)和KEYM(P34)。很多使用FETMX8MQ-C核心板的用……
    • 全志A40i核心板全國產化 照亮動力設備國產化之路
      1閱讀 0條評論 個贊
      國產化三個字近幾年來在電力行業內很火,新的設備、新的項目都開始有國產化的趨勢,要求自主可控,然而很多人只是泛泛地去看待“國產化”這三個字而沒有去深究它的重要性。自主可控有多重要?今天,我們就來認真地聊……
    • 企業操作和維護實踐-丟棄docker構建
      15閱讀 0條評論 個贊
      本章目錄目錄0x00前言簡述快速介紹什么是Kaniko?為啥用Kaniko?Kaniko是如何工作的?Kaniko已知功能問題kaniko構建上下文kaniko緩存構建0x01部署使用環境……
    • 人人都能讀懂的源代碼——那些關于DOM的常見鉤子包(二)
      0閱讀 0條評論 個贊
      本文是深入淺出ahooks源碼系列文章的第十五篇,該系列已整理成文檔-地址。覺得還不錯,給個star支持一下哈,Thanks。本篇接著針對關于DOM的各個Hook封裝進行解讀。useFul……
    • 新一代網絡請求庫:python-httpx庫
      0閱讀 0條評論 個贊
      目錄httpx庫一、概述1、簡介2、命令行模式3、快速開始3.1get請求3.2post請求3.2.1表單3.2.2文件3.2.3JSON3.2.4二進制3.3響應處理3.4流……
    • 【云原生】-碼頭工人容器遷移神諭到關系型數據庫
      0閱讀 0條評論 個贊
      文章目錄前言??1.創建專用網絡??2.Oracle12C部署?2.1鏡像下載?2.2容器創建?2.3創建業務用戶?2.4監聽啟動??3.MySQL8部署?3.1容器……
    • MySQL性能調優和優化技術
      0閱讀 0條評論 個贊
      介紹MySQL是一種流行的開源數據庫應用程序,它以一種有意義且易于訪問的方式存儲和構造數據。對于大型應用程序,龐大的數據量可能會導致性能問題。本指南提供了一些關于如何提高MySQL數據庫性能的調……
    • SpringMVC 03: 請求和響應的亂碼解決 + SpringMVC響應Ajax請求
      1閱讀 0條評論 個贊
      請求或響應的中文亂碼問題tomcat9解決了get請求和響應的中文亂碼問題,但是沒有解決post請求或響應的中文亂碼問題tomcat10解決了get和post請求以及響應的中文亂碼問題考慮到實際項目中……
    • MySQL查詢性能優化指數下推的七大武器
      0閱讀 0條評論 個贊
      前面已經講了MySQL的其他查詢性能優化方式,沒看過可以去了解一下:MySQL查詢性能優化七種武器之索引潛水MySQL查詢性能優化七種武器之鏈路追蹤今天要講的是MySQL的另一種查詢性能優化方式—索……
    • 自動化測試選擇Python還是Java?
      0閱讀 0條評論 個贊
      你好,我是測試蔡坨坨。今天,我們來聊一聊測試人員想要進階,想要做自動化測試,甚至測試開發,如何選擇編程語言。前言自動化測試,這幾年行業內的熱詞,也是測試人員進階的必備技能,更是軟件測試未來發展的趨勢?!?/div>
    • 二戰MySQL數據庫【升華】
      0閱讀 0條評論 個贊
      MYSQL入門系列——第二篇1.篩選條件:(1)比較運算符:(2)邏輯運算符:(3)其他操作:1.排序:2.限制:拓展:3.去重:4.模糊查詢:(like'%')5.范圍查詢:2.聚合與分組(重點……
    • SQL Server的常用分頁SQL
      0閱讀 0條評論 個贊
      今天無聊和朋友討論分頁,發現網上好多都是錯的。網上經常查到的那個TopNotin或者Max大部分都不實用,很多都忽略了Order和性能問題。為此上網查了查,順帶把2000和2012版本的也補上……
    • smile——Java機器學習引擎
      2閱讀 0條評論 個贊
      資源https://haifengl.github.io/https://github.com/haifengl/smile介紹Smile(統計機器智能和學習引擎)是一個基于Java和Scala的快速……
    • Python系列入門(四)別傻了 別糊涂了:鏈表、元組、字典、集合的區別
      0閱讀 0條評論 個贊
      總結分析列表、元組、字典、集合的相同與區別之處,只有徹底分清之后,就會在應用的時候,得心應手。四句話總結列表是一個有序且可更改的集合,允許重復成員。元組是一個有序且不可更改的集合,允許重復成員。集合是……
    • SpringMVC 01: SpringMVC第一個SpringMVC項目
      0閱讀 0條評論 個贊
      SpringMVCSpringMVC概述:是基于MVC開發模式的框架,用來優化控制器是Spring家族的一員,也具備IOC和AOP什么是MVC:它是一種開發模式,是模型視圖控制器的簡稱,所有的web應……
    • 基于ASP.NET核心6.0的簡潔架構
      0閱讀 0條評論 個贊
      背景最近嘗試錄制了一個系列視頻:《ASP.NETCore6.0+Vue.js3實戰開發》,本節是視頻內部整潔架構的理論和實戰的文字稿。因為在錄制之前,我通常會編寫完整的文字內容作為視頻文案,這……
    • sql server系統表的詳細說明
      0閱讀 0條評論 個贊
      sysaltfiles主數據庫保存數據庫的文件syscharsets主數據庫字符集與排序順序sysconfigures主數據庫配置選項syscurconfigs主數據庫當前配置選項sysdatab……
    • 用Python實現廣度優先搜索
      3閱讀 0條評論 個贊
      圖是一種善于處理關系型數據的數據結構,使用它可以很輕松地表示數據之間是如何關聯的圖的實現形式有很多,最簡單的方法之一就是用散列表背景圖有兩種經典的遍歷方式:廣度優先搜索和深度優先搜索。兩者是相似的。實……
    • 三萬字肝爆《數據倉庫體系》
      0閱讀 0條評論 個贊
      文章很長,前言一定要看擁有本篇文章,意味著你擁有一本完善的書籍,本篇文章整理了數據倉庫領域,幾乎所有的知識點,文章內容主要來源于以下幾個方面:源于「數據倉庫交流群」資深數據倉庫工程師的交流討論,如《s……
    最近發布資訊
    更多
    十八禁试看120秒做受