Django前后端打通

跨域問題

【 0 】前言

? image-20240511083754769

? 同源策略(Same Origin Policy)是瀏覽器安全策略的重要組成部分,它限制了來自不同源的網頁之間的數據交互,以防止惡意攻擊。當一個網頁嘗試執行與它的源(即協議、域名和端口)不一致的請求時,瀏覽器會出于安全考慮攔截這個請求。

? 跨域資源共享(CORS, Cross-Origin Resource Sharing)是一個W3C規范,它允許某些跨源請求,如Ajax,從而克服了Ajax只能同源使用的限制。CORS需要瀏覽器和服務器同時支持,基本思想是使用自定義的HTTP頭來讓瀏覽器和服務器進行通信。

? 在Django項目中解決跨域問題,可以通過多種方法,包括手動編寫中間件以及使用第三方庫。你給出的示例展示了如何手動編寫一個CORS中間件,以及如何使用django-cors-headers這個流行的第三方庫來簡化CORS的設置。

手動編寫CORS中間件

? 中間件代碼示例中,通過向響應頭中添加適當的CORS相關頭部,允許來自任何源的請求("Access-Control-Allow-Origin": "*")。同時,對于OPTIONS請求(預檢請求),該中間件還允許所有的方法和頭部。

使用django-cors-headers

  1. 安裝庫:pip install django-cors-headers
  2. settings.py中添加'corsheaders'INSTALLED_APPS
  3. settings.pyMIDDLEWARE中添加'corsheaders.middleware.CorsMiddleware',并確保它在其他中間件之前(特別是在CommonMiddleware之前)。
  4. 配置CORS選項。例如,設置CORS_ORIGIN_ALLOW_ALLTrue來允許所有源的請求,或者你可以指定一個允許源的列表。CORS_ALLOW_METHODSCORS_ALLOW_HEADERS分別定義了允許的HTTP方法和頭部。

? 請注意,出于安全考慮,通常不建議在生產環境中設置CORS_ORIGIN_ALLOW_ALLTrue,除非你完全理解可能的安全風險。在生產環境中,最好明確指定允許的源。

? 另外,值得注意的是,雖然CORS解決了瀏覽器端的跨域問題,但服務器端仍然需要驗證請求的有效性,以防止潛在的安全威脅,如CSRF攻擊。因此,即使啟用了CORS,也不應忽視服務器端的安全性措施。

# 同源策略(Same origin policy)是一種約定,它規定了 請求的url地址,必須與瀏覽器上的url地址處于同域上,也就是域名,端口,協議相同,如果不一致,請求會發送成功,后端會正常響應,但是瀏覽器會攔截#  瀏覽器對非同源請求返回的結果做了攔截
# 只要做前后端分離,就會出跨域# 解決跨域問題-CORS :跨域資源共享  咱們講的方式   向響應頭中加數據,允許跨域- 后端代碼處理- nginx代理-JSONP :利用有的標簽沒有跨域問題 script  img-websocket:長鏈接,不存在跨域-前端代理:開發階段用,上線不用# cors如何解決跨域-需要服務端支持---》就是服務端再響應頭中加數據即可# CORS基本流程CORS請求分成兩類:簡單請求(simple request)和非簡單請求(not-so-simple request)簡單請求,只發送一次:非簡單請求發送兩次,第一次是OPTIONS預檢請求,第二次是真正的請求
# 什么是簡單,什么是非簡單
#請求方法是以下三種方法之一:HEADGETPOST
# HTTP的頭信息不超出以下幾種字段:AcceptAccept-LanguageContent-LanguageLast-Event-IDContent-Type:只限于三個值application/x-www-form-urlencoded、multipart/form-data、text/plain# 請求頭中帶了 token ,所有請求都是非簡單### 解決跨域---統一寫個中間件--》處理所有跨域
from django.utils.deprecation import MiddlewareMixin
class CorsMiddleWare(MiddlewareMixin):def process_response(self,request,response):if request.method=="OPTIONS":#可以加*response["Access-Control-Allow-Headers"]="*"res['Access-Control-Allow-Methods'] = '*'response["Access-Control-Allow-Origin"] = "*"return response# 第三方解決方案# 1、使用pip安裝pip install django-cors-headers#2、添加到setting的app中INSTALLED_APPS = (...'corsheaders',...)#3、添加中間件MIDDLEWARE = [  ...'corsheaders.middleware.CorsMiddleware',...]
4、setting下面添加下面的配置
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = ('DELETE','GET','OPTIONS','PATCH','POST','PUT','VIEW',
)CORS_ALLOW_HEADERS = ('XMLHttpRequest','X_FILENAME','accept-encoding','authorization','content-type','dnt','origin','user-agent','x-csrftoken','x-requested-with','Pragma','token'
)

【 1 】解釋

? Access-Control-Allow-HeadersAccess-Control-Allow-MethodsAccess-Control-Allow-Origin 是三個與跨源資源共享(CORS)相關的 HTTP 響應頭。它們各自有不同的作用和使用方法。

1. Access-Control-Allow-Origin

作用

  • 用于指定哪些源(域名、協議和端口)有權限訪問該資源。

使用方法

  • 如果服務器希望允許來自特定源的請求,如 https://example.com,可以返回以下響應頭:
Access-Control-Allow-Origin: https://example.com
  • 如果服務器希望允許來自任何源的請求(這通常在生產環境中是不安全的),可以返回:
Access-Control-Allow-Origin: *

2. Access-Control-Allow-Methods

作用

  • 列出哪些 HTTP 方法(如 GET、POST、PUT、DELETE 等)允許跨源請求。

使用方法

  • 如果服務器只允許 GET 和 POST 方法,可以返回以下響應頭:
Access-Control-Allow-Methods: GET, POST
  • 這個響應頭通常與預檢請求(OPTIONS 請求)一起使用,以檢查服務器是否允許跨源請求中使用的特定 HTTP 方法。

3. Access-Control-Allow-Headers

作用

  • 用于告知瀏覽器在跨域請求中,所允許的請求頭字段(Request Header)。

使用方法

  • 如果瀏覽器請求包括 Access-Control-Request-Headers 字段,則 Access-Control-Allow-Headers 字段是必需的。它的值是一個逗號分隔的字符串,表明服務器支持的所有頭信息字段,不限于瀏覽器在“預檢”中請求的字段。
  • 例如,如果服務器允許跨域請求時使用的請求頭字段是 Content-TypeAuthorization,可以返回以下響應頭:
Access-Control-Allow-Headers: Content-Type, Authorization

總結

  • Access-Control-Allow-Origin 用于指定哪些源可以訪問資源。
  • Access-Control-Allow-Methods 用于指定哪些 HTTP 方法允許跨源請求。
  • Access-Control-Allow-Headers 用于告知瀏覽器在跨域請求中,所允許的請求頭字段。

? 這三個響應頭通常一起使用,以確保跨源請求的安全性和可訪問性。同時,它們也遵循 CORS 規范,確保瀏覽器和服務器之間的正確交互。

【 2 】跨域問題

【 1 】笨辦法

  • Access-Control-Allow-Origin

  • 在子路由的視圖類

from rest_framework.views import APIView
from lufy.utils.utils_response import APIResponse 	class CoreView(APIView):def get(self, request, *args, **kwargs):# return APIResponse(name="shazi",password='123123132',token='asdas.da.dasd')# return APIResponse(results=[{"user":'132'},{"hobby":['music','running']}])return APIResponse(headers={"hobby":['music','running']})
  • 在HomeView.vue

<template><div class="home"><h1>首頁</h1><!-- 在這里你可以添加一些內容來顯示獲取到的數據 --><div v-if="dataFromServer"><!-- 使用 dataFromServer 的數據來渲染內容 --><!-- 假設返回的數據是一個對象,并且你想顯示其某個屬性,例如 message --><p>{{ dataFromServer.message }}</p></div></div>
</template><script setup>
import { reactive, onMounted } from 'vue';
import axios from 'axios';// 使用 reactive 來創建響應式的數據對象
const res = reactive({message: ''
});// 在 onMounted 生命周期鉤子中發送請求
onMounted(async () => {try {const response = await axios.get('http://127.0.0.1:8000/user/option/', {headers: {// token: 'asd.fas.sadas' // 在請求頭中添加自定義的 token}});res.message = response.data.message;// 這里可以處理響應的其他數據console.log(response);} catch (error) {console.error('Error fetching data:', error);// 在這里你可以選擇以某種方式通知用戶或處理錯誤}
});
</script><style scoped>
/* 你的樣式代碼 */
</style>

image-20240511172929754

  • 解決方法

from rest_framework.views import APIView
from lufy.utils.utils_response import APIResponse 
class CoreView(APIView):def get(self, request, *args, **kwargs):# # return APIResponse(headers={"hobby":['music','running']})# No 'Access-Control-Allow-Origin' header is present on the requested resource.return APIResponse(headers={"Access-Control-Allow-Origin": '*'})

image-20240511175030361

  • Access-Control-Allow-Headers

  • 用于告知瀏覽器在跨域請求中,所允許的請求頭字段

  • urls.py

from django.urls import path
from . import views
from .views import LoggerView, ExceptionView,ResponseView,CoreView,core_viewurlpatterns = [# 日志path('logg/', LoggerView.as_view(), name='home'),# 異常path('except/', ExceptionView.as_view()),# 響應方法path('ponse/', ResponseView.as_view()),# 跨域path('core/', CoreView.as_view()),path('option/', core_view),]
  • views.py

from rest_framework.views import APIView
from lufy.utils.utils_response import APIResponse def core_view(request):res = HttpResponse("ok")res['Access-Control-Allow-Origin'] = '*'if request.method =='OPTIONS':res['Access-Control-Allow-Headers'] = '*'return res

image-20240511191016929

  • 我現在要使用別的請求方法比如put、delete

<script setup>
import { reactive, onMounted } from 'vue';
import axios from 'axios';// 使用 reactive 來創建響應式的數據對象
const res = reactive({message: ''
});// 在 onMounted 生命周期鉤子中發送請求
onMounted(async () => {try {const response = await axios.put('http://127.0.0.1:8000/user/option/', {headers: {token: 'asd.fas.sadas' // 在請求頭中添加自定義的 token}});res.message = response.data.message;// 這里可以處理響應的其他數據console.log(response);} catch (error) {console.error('Error fetching data:', error);// 在這里你可以選擇以某種方式通知用戶或處理錯誤}
});
</script>

image-20240511191419095

  • 我們只需要添加Access-Control-Allow-Methods

  • res['Access-Control-Allow-Headers'] = '*'
    
def core_view(request):res = HttpResponse("ok")res['Access-Control-Allow-Origin'] = '*'if request.method =='OPTIONS':res['Access-Control-Allow-Headers'] = '*'res['Access-Control-Allow-Methods'] = '*'return res
# 注意注釋跨域403
MIDDLEWARE = ['django.middleware.security.SecurityMiddleware','django.contrib.sessions.middleware.SessionMiddleware','django.middleware.common.CommonMiddleware',# 'django.middleware.csrf.CsrfViewMiddleware','django.contrib.auth.middleware.AuthenticationMiddleware','django.contrib.messages.middleware.MessageMiddleware','django.middleware.clickjacking.XFrameOptionsMiddleware',
]

image-20240511192131238

image-20240511192156561

? 非簡單請求(non-simple requests)在CORS(跨源資源共享)中,指的是不滿足簡單請求條件的請求。簡單請求和非簡單請求的區分主要是基于HTTP請求的一些特性,而不僅僅是基于發送了幾次請求。

簡單請求需要滿足以下條件:

  1. 請求方法只能是以下幾種之一:HEAD、GET、POST。
  2. HTTP頭信息不超出以下幾種字段:
    • Accept
    • Accept-Language
    • Content-Language
    • Last-Event-ID
    • Content-Type:只限于三個值 application/x-www-form-urlencodedmultipart/form-datatext/plain

? 如果HTTP請求不滿足以上條件,那么它就是一個非簡單請求。

? 非簡單請求在瀏覽器發送真正的請求之前,會首先發送一個預檢請求(preflight request),請求方法是OPTIONS。預檢請求會詢問服務器是否允許該跨域請求。服務器響應預檢請求時,需要包含一些CORS相關的響應頭信息,比如 Access-Control-Allow-OriginAccess-Control-Allow-MethodsAccess-Control-Allow-Headers 等,來告知瀏覽器該跨域請求是否被允許。

? 所以,非簡單請求并不是看你發送了幾次請求,而是看請求的HTTP方法、頭信息等是否滿足簡單請求的條件。如果不滿足,瀏覽器就會發送預檢請求,這增加了一次額外的HTTP請求。

【 2 】自定義中間件

  • views.py

from rest_framework.views import APIView
from lufy.utils.utils_response import APIResponse 
def core_view(request):res = HttpResponse("ok")return res
  • urls.py

from django.urls import path
from . import views
from .views import core_viewurlpatterns = [# optionpath('option/', core_view),]
  • 在utils/utils.
## 中間件###
from django.utils.deprecation import MiddlewareMixin
class CorsMiddleWare(MiddlewareMixin):def process_response(self,request,response):if request.method=="OPTIONS":#可以加*response["Access-Control-Allow-Headers"]="*"response['Access-Control-Allow-Methods'] = '*'response["Access-Control-Allow-Origin"] = "*"return response
  • 配置文件新的dev.py

MIDDLEWARE = ['utils.utils_middleware.CorsMiddleWare',
]
<template><div class="home"><h1>首頁</h1><!-- 在這里你可以添加一些內容來顯示獲取到的數據 --><!-- 使用 dataFromServer 的數據來渲染內容 --><!-- 假設返回的數據是一個對象,并且你想顯示其某個屬性,例如 message --><p>{{ res.message }}</p></div></template><script setup>
import { reactive, onMounted } from 'vue';
import axios from 'axios';// 使用 reactive 來創建響應式的數據對象
const res = reactive({message: ''
});// 在 onMounted 生命周期鉤子中發送請求
onMounted(async () => {try {const response = await axios.put('http://127.0.0.1:8000/user/option/', {headers: {token: 'asd.fas.sadas' // 在請求頭中添加自定義的 token}});res.message = response.data.message;// 這里可以處理響應的其他數據console.log(response);} catch (error) {console.error('Error fetching data:', error);// 在這里你可以選擇以某種方式通知用戶或處理錯誤}
});
</script><style scoped>
/* 你的樣式代碼 */
</style>

image-20240511193557916

【 3 】第三方app解決

# 1、使用pip安裝
pip install django-cors-headers# 2、添加到setting的app中
INSTALLED_APPS = (...'corsheaders',...
)
# 3、添加中間件
MIDDLEWARE = [  ...'corsheaders.middleware.CorsMiddleware',...
]
# 4、setting下面添加下面的配置
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_METHODS = ('DELETE','GET','OPTIONS','PATCH','POST','PUT','VIEW',
)CORS_ALLOW_HEADERS = ('XMLHttpRequest','X_FILENAME','accept-encoding','authorization','content-type','dnt','origin','user-agent','x-csrftoken','x-requested-with','Pragma','token',
)### 中間件源碼分析
if conf.CORS_ALLOW_ALL_ORIGINS and not conf.CORS_ALLOW_CREDENTIALS:response[ACCESS_CONTROL_ALLOW_ORIGIN] = "*"
if request.method == "OPTIONS":response[ACCESS_CONTROL_ALLOW_HEADERS] = ", ".join(conf.CORS_ALLOW_HEADERS)response[ACCESS_CONTROL_ALLOW_METHODS] = ", ".join(conf.CORS_ALLOW_METHODS)
  • 1、使用pip安裝

    # pip install django-cors-headers
    

    image-20240511193807957

  • 2、添加到setting的app中

INSTALLED_APPS = (...'corsheaders',...)
  • 3、添加中間件

    MIDDLEWARE = [  ...'corsheaders.middleware.CorsMiddleware',...
    ]
    
  • 4、setting下面添加下面的配置(放在新建的common_settings)

    CORS_ORIGIN_ALLOW_ALL = True
    CORS_ALLOW_METHODS = ('DELETE','GET','OPTIONS','PATCH','POST','PUT','VIEW',
    )CORS_ALLOW_HEADERS = ('XMLHttpRequest','X_FILENAME','accept-encoding','authorization','content-type','dnt','origin','user-agent','x-csrftoken','x-requested-with','Pragma','token',
    )
    

    image-20240511194116226

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

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

相關文章

【區分vue2和vue3下的element UI Carousel 走馬燈組件,分別詳細介紹屬性,事件,方法如何使用,并舉例】

在 Vue 2 中&#xff0c;我們通常使用 Element UI&#xff0c;而在 Vue 3 中&#xff0c;我們則使用 Element Plus 作為其替代品。對于 Carousel 走馬燈組件&#xff0c;這兩個庫提供了相似的功能&#xff0c;但在 Vue 2 和 Vue 3 的上下文中&#xff0c;它們的屬性、事件和方法…

C\C++ 終端輸出帶有顏色的字符

終端顯示帶有顏色的字符 終端顯示帶有顏色的字符 終端顯示帶有顏色的字符背景&#xff1a;測試機器&#xff0c;win10系統&#xff0c; VS2022編寫字體設置不同的顏色背景色光標移動 &#xff08;這個用的估計不是很多&#xff09;字體設置動態顯示C cout 也可以測試代碼準確的…

接口基礎知識3:詳解url

課程大綱 一、定義 URL即訪問的鏈接&#xff0c;是Uniform Resource Locator的縮寫&#xff0c;譯為"統一資源定位符"。 URL是一種URI&#xff0c;它標識一個互聯網資源&#xff0c;并指定對其進行操作或獲取該資源的方法。可能通過對主要訪問手段的描述&#xff0c…

SpringBoot詳細解析

1.什么是springboot springboot也是spring公司開發的一款框架。為了簡化spring項目的初始化搭建的。那么spring對應springboot有什么缺點呢&#xff1f; spring項目搭建的缺點: 配置麻煩依賴tomcat啟動慢 2.springboot的特點 自動配置 Spring Boot的自動配置是一個運行時&…

Docker 安裝ros 使用rviz 等等圖形化程序

Docker 安裝ros 使用rviz 等等圖形化程序 ubuntu 版本與ros 發行版本對應 如何安裝其它版本ros 此時考慮使用docker 易于維護 地址&#xff1a; https://hub.docker.com/r/osrf/ros 我主機是 ubuntu22.04 使用這個標簽 melodic-desktop-full 1 clone 鏡像到本機 docker pu…

Android OkHttp3中HttpLoggingInterceptor使用

目錄 一 概述1.1 日志級別 二 使用2.1 引入依賴2.2 創建對象2.3 添加攔截器 三 結果展示3.1 日志級別為BODY3.2 日志級別為BASIC3.3 日志級別為HEADERS 參考 一 概述 HttpLoggingInterceptor是OkHttp3提供的攔截器&#xff0c;用來記錄HTTP請求和響應的詳細信息。 1.1 日志級…

基于IDEA的Lombok插件安裝及簡單使用

lombok介紹 Lombok能以注解形式來簡化java代碼&#xff0c;提高開發效率。開發中經常需要寫的javabean&#xff0c;都需要花時間去添加相應的getter/setter&#xff0c;也許還要去寫構造器、equals等方法&#xff0c;而且需要維護。而Lombok能通過注解的方式&#xff0c;在編譯…

Spring AOP 實現 Excel 導出統一處理

你好&#xff0c;我是柳岸花開。在實際開發中&#xff0c;經常會遇到需要導出 Excel 數據的需求。為了避免代碼重復&#xff0c;我們可以使用 Spring AOP&#xff08;面向切面編程&#xff09;來實現 Excel 導出的統一處理。本文將介紹如何使用 Spring AOP 在項目中統一處理 Ex…

【學習筆記】無人機(UAV)在3GPP系統中的增強支持(十三)-更換無人機控制器

引言 本文是3GPP TR 22.829 V17.1.0技術報告&#xff0c;專注于無人機&#xff08;UAV&#xff09;在3GPP系統中的增強支持。文章提出了多個無人機應用場景&#xff0c;分析了相應的能力要求&#xff0c;并建議了新的服務級別要求和關鍵性能指標&#xff08;KPIs&#xff09;。…

枚舉的高階用法之枚舉里寫方法以及注入spring的bean

1、前言 一般我們使用枚舉都是用來定義一些常量。比如我們需要一個表示訂單類(pc訂單、手機訂單)的常量,那我們就可以使用枚舉來實現,如下: AllArgsConstructor public enum OrderTypeEnum{PC("PC", "電腦端"),PHONE("PHONE", "手機端&quo…

[計網初識2]web的3個核心標準html,url,http

學習內容 HTML,URL,HTTP的構成 1.規范web的3個核心標準&#xff1f; HTML(Hyper Text Markup Language),規范網頁內容和版面布局的表示標準。URL(Uniform Resource Locator)&#xff0c;規范網頁識別符格式和含義的表示標準。HTTP(HyperText Transfer Protocl),規范游覽器如…

JIRA的高級搜索JIRA Query Language(JQL)詳解

JIRA的高級搜索功能非常強大&#xff0c;允許用戶通過JIRA Query Language&#xff08;JQL&#xff09;來構建復雜的查詢。以下是一些常用的高級搜索用法和示例&#xff1a; 1. 基本語法 JQL的基本語法包括字段、運算符和值的組合。例如&#xff1a; field operator value2.…

<數據集>UA-DETRAC車輛識別數據集<目標檢測>

數據集格式&#xff1a;VOCYOLO格式 圖片數量&#xff1a;20500張 標注數量(xml文件個數)&#xff1a;20500 標注數量(txt文件個數)&#xff1a;20500 標注類別數&#xff1a;4 標注類別名稱&#xff1a;[car, van, others, bus] 序號類別名稱圖片數框數1car201871259342…

鋇錸ARMxy控制器在智能網關中的應用

隨著IoT物聯網技術的飛速發展&#xff0c;智能網關作為連接感知層與網絡層的樞紐&#xff0c;可以實現感知網絡和通信網絡以及不同類型感知網絡之間的協議轉換。鋇錸技術的ARMxy系列控制器憑借其高性能、低功耗和高度靈活性的特點&#xff0c;在智能網關中發揮了關鍵作用&#…

數據結構回顧(Java)

1.數組 線性表 定義的方式 int[] anew int[10] 為什么查詢快&#xff1f; 1.可以借助O(1)時間復雜度訪問某一元素&#xff0c; 2.地址連續&#xff0c;邏輯連續 3.數組長度一旦確定就不可以被修改 當需要擴容的時候需要將老數組的內容復制過來 在Java中數組是一個對象 Ar…

bug定位策略

前提--用戶環境層面 hosts異常&#xff1a;hosts文件主要是加快某個域名或者網站的解析速度&#xff0c;從而達到快速訪問的作用&#xff0c;也可以屏蔽網站。hosts異常可能會導致部分網頁無法訪問&#xff0c;能夠加載&#xff0c;但是網頁無法正常顯示&#xff1b;測試環境臟…

記錄些Redis題集(2)

Redis 的多路IO復用 多路I/O復用是一種同時監聽多個文件描述符&#xff08;如Socket&#xff09;的狀態變化&#xff0c;并能在某個文件描述符就緒時執行相應操作的技術。在Redis中&#xff0c;多路I/O復用技術主要用于處理客戶端的連接請求和讀寫操作&#xff0c;以實現高并發…

Python_使用pyecharts構建折線圖

Pyecharts簡介 Pyecharts是一款將python與echarts結合的強大的數據可視化工具&#xff0c;使用 pyecharts 可以生成獨立的網頁&#xff0c;也可以在 flask , Django 中集成使用。echarts &#xff1a;百度開源的一個數據可視化 JS 庫&#xff0c;主要用于數據可視化。pyechart…

嵌入式linux相機 框圖

攝像頭讀取數據顯示到LCD流程 重點&#xff1a;攝像頭數據&#xff08;yuyv&#xff0c;mjpeg&#xff0c;rgb&#xff09;&#xff08;640,320&#xff09;與LCD顯示數據&#xff08;RGB&#xff09;&#xff08;480&#xff0c;240&#xff09;不同&#xff1b;需要轉換&…

ReactRouter v6升級的步驟

React Router v6 引入了一個 Routes 組件&#xff0c;它有點像 Switch &#xff0c;但功能要強大得多。與 Switch 相比&#xff0c; Routes 的主要優勢在于&#xff1a; <Routes> 中的所有 <Route> 和 <Link> 都是相對的。這導致在 <Route path> 和 &…