從前後端的角度分析options預檢請求

来源:https://www.cnblogs.com/huaweiyun/archive/2023/05/16/17405767.html
-Advertisement-
Play Games

options預檢請求是幹嘛的?options請求一定會在post請求之前發送嗎?前端或者後端開發需要手動干預這個預檢請求嗎?不用文檔定義堆砌名詞,從前後端角度單獨分析,大白話帶你瞭解! ...


摘要:options預檢請求是幹嘛的?options請求一定會在post請求之前發送嗎?前端或者後端開發需要手動干預這個預檢請求嗎?不用文檔定義堆砌名詞,從前後端角度單獨分析,大白話帶你瞭解!

本文分享自華為雲社區《從前後端的角度分析options預檢請求——打破前後端聯調的理解障礙》,作者: 磚業洋__ 。

options預檢請求是幹嘛的?options請求一定會在post請求之前發送嗎?前端或者後端開發需要手動干預這個預檢請求嗎?不用文檔定義堆砌名詞,從前後端角度單獨分析,大白話帶你瞭解!

從前端的角度看options——post請求之前一定會有options請求?信口雌黃!

你是否經常看到這種跨域請求錯誤?

這是因為伺服器不允許跨域請求,這裡會深入講一講OPTIONS請求。

只有在滿足一定條件的跨域請求中,瀏覽器才會發送OPTIONS請求(預檢請求)。這些請求被稱為“非簡單請求”。反之,如果一個跨域請求被認為是“簡單請求”,那麼瀏覽器將不會發送OPTIONS請求。

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

  1. 只使用以下HTTP方法之一:GET、HEAD或POST。
  2. 只使用以下HTTP頭部:Accept、Accept-Language、Content-Language、Content-Type。
  3. Content-Type的值僅限於:application/x-www-form-urlencoded、multipart/form-data或text/plain。

如果一個跨域請求不滿足以上所有條件,那麼它被認為是非簡單請求。對於非簡單請求,瀏覽器會在實際請求(例如PUT、DELETE、PATCH或具有自定義頭部和其他Content-Type的POST請求)之前發送OPTIONS請求(預檢請求)。

舉個例子吧,口嗨半天是看不懂的,讓我們看看 POST請求在什麼情況下不發送OPTIONS請求

提示:當一個跨域POST請求滿足簡單請求條件時,瀏覽器不會發送OPTIONS請求(預檢請求)。以下是一個滿足簡單請求條件的POST請求示例:

// 使用Fetch API發送跨域POST請求
fetch("https://example.com/api/data", {
  method: "POST",
  headers: {
 "Content-Type": "application/x-www-form-urlencoded"
 },
  body: "key1=value1&key2=value2"
})
 .then(response => response.json())
 .then(data => console.log(data))
 .catch(error => console.error("Error:", error));

在這個示例中,我們使用Fetch API發送了一個跨域POST請求。請求滿足以下簡單請求條件:

  1. 使用POST方法。
  2. 使用的HTTP頭部僅包括Content-Type。
  3. Content-Type的值為"application/x-www-form-urlencoded",屬於允許的三種類型之一(application/x-www-form-urlencoded、multipart/form-data或text/plain)。

因為這個請求滿足了簡單請求條件,所以瀏覽器不會發送OPTIONS請求(預檢請求)。

我們再看看什麼情況下POST請求之前會發送OPTIONS請求,同樣用代碼說明,進行對比

提示:在跨域請求中,如果POST請求不滿足簡單請求條件,瀏覽器會在實際POST請求之前發送OPTIONS請求(預檢請求)。

// 使用Fetch API發送跨域POST請求
fetch("https://example.com/api/data", {
  method: "POST",
  headers: {
 "Content-Type": "application/json",
 "X-Custom-Header": "custom-value"
 },
  body: JSON.stringify({
    key1: "value1",
    key2: "value2"
 })
})
 .then(response => response.json())
 .then(data => console.log(data))
 .catch(error => console.error("Error:", error));

在這個示例中,我們使用Fetch API發送了一個跨域POST請求。請求不滿足簡單請求條件,因為:

  1. 使用了非允許範圍內的Content-Type值("application/json" 不屬於 application/x-www-form-urlencoded、multipart/form-data或text/plain)。
  2. 使用了一個自定義HTTP頭部 “X-Custom-Header”,這不在允許的頭部列表中。

因為這個請求不滿足簡單請求條件,所以在實際POST請求之前,瀏覽器會發送OPTIONS請求(預檢請求)。

你可以按F12直接在Console輸入查看Network,儘管這個網址不存在,但是不影響觀察OPTIONS請求,對比一下我這兩個例子。

總結:當進行非簡單跨域POST請求時,瀏覽器會在實際POST請求之前發送OPTIONS預檢請求,詢問伺服器是否允許跨域POST請求。如果伺服器不允許跨域請求,瀏覽器控制台會顯示跨域錯誤提示。如果伺服器允許跨域請求,那麼瀏覽器會繼續發送實際的POST請求。而對於滿足簡單請求條件的跨域POST請求,瀏覽器不會發送OPTIONS預檢請求。

後端可以通過設置Access-Control-Max-Age來控制OPTIONS請求的發送頻率。OPTIONS請求沒有響應數據(response data),這是因為OPTIONS請求的目的是為了獲取伺服器對於跨域請求的配置信息(如允許的請求方法、允許的請求頭部等),而不是為了獲取實際的業務數據,OPTIONS請求不會命中後端某個介面。因此,當伺服器返回OPTIONS響應時,響應中主要包含跨域配置信息,而不會包含實際的業務數據

本地調試一下,前端發送POST請求,後端在POST方法裡面打斷點調試時,也不會阻礙OPTIONS請求的返回

從後端的角度看options——post請求之前一定會有options請求?胡說八道!

在配置跨域時,伺服器需要處理OPTIONS請求,以便在響應頭中返回跨域配置信息。這個過程通常是由伺服器的跨域中間件(Node.js—Express框架的cors中間件、Python—Flask框架的flask_cors擴展)或過濾器(Java—SpringBoot框架的跨域過濾器)自動完成的,而無需開發人員手動處理。

以下是使用Spring Boot的一個跨域過濾器,供參考

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
 public CorsConfig() {
 }
 @Bean
 public CorsFilter corsFilter() {
 // 1. 添加cors配置信息
 CorsConfiguration config = new CorsConfiguration();
 // Response Headers裡面的Access-Control-Allow-Origin: http://localhost:8080
 config.addAllowedOrigin("http://localhost:8080");
 // 其實不建議使用*,允許所有跨域
 config.addAllowedOrigin("*");
 // 設置是否發送cookie信息,在前端也可以設置axios.defaults.withCredentials = true;表示發送Cookie,
 // 跨域請求要想帶上cookie,必須要請求屬性withCredentials=true,這是瀏覽器的同源策略導致的問題:不允許JS訪問跨域的Cookie
 /**
         * withCredentials前後端都要設置,後端是setAllowCredentials來設置
         * 如果後端設置為false而前端設置為true,前端帶cookie就會報錯
         * 如果後端為true,前端為false,那麼後端拿不到前端的cookie,cookie數組為null
         * 前後端都設置withCredentials為true,表示允許前端傳遞cookie到後端。
         * 前後端都為false,前端不會傳遞cookie到服務端,後端也不接受cookie
         */
 // Response Headers裡面的Access-Control-Allow-Credentials: true
 config.setAllowCredentials(true);
 // 設置允許請求的方式,比如get、post、put、delete,*表示全部
 // Response Headers裡面的Access-Control-Allow-Methods屬性
 config.addAllowedMethod("*");
 // 設置允許的header
 // Response Headers裡面的Access-Control-Allow-Headers屬性,這裡是Access-Control-Allow-Headers: content-type, headeruserid, headerusertoken
 config.addAllowedHeader("*");
 // Response Headers裡面的Access-Control-Max-Age:3600
 // 表示下回同一個介面post請求,在3600s之內不會發送options請求,不管post請求成功還是失敗,3600s之內不會再發送options請求
 // 如果不設置這個,那麼每次post請求之前必定有options請求
 config.setMaxAge(3600L);
 // 2. 為url添加映射路徑
 UrlBasedCorsConfigurationSource corsSource = new UrlBasedCorsConfigurationSource();
 // /**表示該config適用於所有路由
 corsSource.registerCorsConfiguration("/**", config);
 // 3. 返回重新定義好的corsSource
 return new CorsFilter(corsSource);
 }
}

這裡setMaxAge方法來設置預檢請求(OPTIONS請求)的有效期,當瀏覽器第一次發送非簡單的跨域POST請求時,它會先發送一個OPTIONS請求。如果伺服器允許跨域,並且設置了Access-Control-Max-Age頭(設置了setMaxAge方法),那麼瀏覽器會緩存這個預檢請求的結果。在Access-Control-Max-Age頭指定的時間範圍內,瀏覽器不會再次發送OPTIONS請求,而是直接發送實際的POST請求,不管POST請求成功還是失敗,在設置的時間範圍內,同一個介面請求是絕對不會再次發送OPTIONS請求的。

後端需要註意的是,我這裡設置允許請求的方法是config.addAllowedMethod("*"),*表示允許所有HTTP請求方法。如果未設置,則預設只允許“GET”和“HEAD”。你可以設置的HTTPMethod為GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE

經過我的測試,OPTIONS無需手動設置,因為單純只設置OPTIONS也無效。如果你設置了允許POST,代碼為config.addAllowedMethod(HttpMethod.POST); 那麼其實已經預設允許了OPTIONS,如果你只允許了GET,嘗試發送POST請求就會報錯。

舉個例子,這裡只允許了GET請求,當我們嘗試發送一個POST非簡單請求,預檢請求返回403,伺服器拒絕了OPTIONS類型的請求,因為你只允許了GET,未配置允許OPTIONS請求,那麼瀏覽器將收到一個403 Forbidden響應,表示伺服器拒絕了該OPTIONS請求,POST請求的狀態顯示CORS error

在Spring Boot中,配置允許某個請求方法(如POST、PUT或DELETE)時,OPTIONS請求通常會被自動允許。這意味著在大多數情況下,後端開發人員不需要特意考慮OPTIONS請求。這種自動允許OPTIONS請求的行為取決於使用的跨域處理庫或配置,最好還是顯式地允許OPTIONS請求。

 

點擊關註,第一時間瞭解華為雲新鮮技術~


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • hive入門到精通 hive部署 啟動Hadoop # 啟動hadoop start-all.sh # 檢查hadoop進程 jps # 檢查各埠 netstat -aplnt | grep java 檢查MySQL是否啟動成功 ps -aux | grep mysql netstat -apln ...
  • 一直從事資料庫相關的工作,對於PG而言最大的問題其實是在運維管理方面,其缺乏有效且直觀成體系的系統表,苦覓良久,今日在PG官網中發現了一款新收錄的免費插件,其提供了數十張系統表,內容涵蓋了從操作系統到資料庫的負載指標、等待事件、會話、客戶端、SQL、SQL執行計劃、超時鎖、長事務、資料庫對象、寫進程 ...
  • MySQL 8.0.28引入的新功能 MySQL 8.0.28開始,新增一個特性,支持監控統計並限制各個連接(會話)的記憶體消耗,避免大量用戶連接因為執行垃圾SQL消耗過多記憶體,造成可能被OOM kill的風險。 首先,需要先設置系統選項 global_connection_memory_tracki ...
  • 有沒有熟悉這樣的場景: 時間已過十一點,空蕩蕩的辦公室只剩自己孤身一人。陪你伏案忙碌的只有電腦風扇被迫營業的“嗡嗡”聲, 窗外的夜正黑得帶勁,仿佛巨獸的口吞噬自己的無奈。 天性善良不善言辭的你,容易被人頤指氣使,加班對你來說是家常便飯。 作為一名碼農,“我到底哪裡錯了,我需要怎麼解決?”是我的座右銘 ...
  • Cypress 是一個非常流行的測試工具,然而實際使用過程中發現一些問題,這裡做些記錄。 問題發現 在 Cypress 下 click 是非常常用的指令,然而在一些特殊場景下 click 並不能如想象中那般正常工作。 比如現在有一個彈窗,我們需要測試在點擊遮罩層時是否可以正常關閉彈窗。 測試代碼比較 ...
  • vue2採用了頭尾雙指針的方法,每次比對時,優先進行頭頭、尾尾、頭尾、尾頭的比對嘗試,如果都沒有命中才會進行亂序比對。 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 Set是一種類似於數組的數據結構,但是它的值是唯一的,即Set中的每個值只會出現一次。Set對象的實例可以用於存儲任何類型的唯一值,從而使它們非常適用於去重。 Map是一種鍵值對集合,其中每個鍵都是唯一的,可以是任何類型,而值則可以是任何 ...
  • 這也太難了吧,怎麼連抄咱也不會抄啊QAQ 看了這麼久的前端,總是感覺看得懂,寫不出來,抄也不會抄 這不,這又抄寫了一個京東電商商城的登錄頁面,本來想好好學習一下頁面的佈局以及編寫結構和思維, 結果html代碼還行,至少可以看的懂,到了css上就完全不知道怎麼設置樣式了,感覺有的樣式完全可以不設置, ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...