寫了半天在本地跑的好好的, 結果上不了線可就糗大了。
筆者剛開始使用的是nginx在配置文档裡填寫了http響應header的, 發現在ajax請求場景下不好控制。打算用tower_http庫的的CorsLayer來解決跨域靈活性的問題, 以下是代碼:
use axum::{routing::{get}, Router}; use axum::http::Method; use sqlx::{MySql, Pool}; use tower_http::cors::{CorsLayer, Any}; pub fn app(pool: Pool<MySql>) -> Router { let cors1 = CorsLayer::new() .allow_methods([Method::GET, Method::POST, Method::OPTIONS]) // 允許一切來源 .allow_origin(Any) .allow_headers(Any); Router::new() .route("/", get(index_controller::handler)) // 首頁 .route("/list_name_avatar", get(some_controller::list_some)) // 某個控制下的方法 .layer(cors1) .with_state(pool) }
上述代碼中, 筆者用到了mysql鏈接池, 會有pool出現, 這一段可以先不看。重點看配置cors槼則時的操作, 首先
allow_methods allow_origin allow_headers是我們常用到的三個方法,分別限定了請求類型、請求站點、請求頭。不想細寫只求跑通就按照我這麽寫。
接下來layer()方法裡面傳入cors1配置。layer的出現順序是有講究的, 因爲Router後面的方法是一層一層包裝和返回的, layer()方法的每次調用只影響它上層的route(), 而不管他下面(外面層)的路由方法。
常見問題總結
筆者用上述玩法是可以跑通的,那爲什麽會遇到405的錯誤呢?
首先看ajax傳輸請求方式是什麽?
如果你檢查ajax的代碼, 以jquery封裝的$.ajax爲例, 通常type字段只有get和post兩種, 例如:
$.ajax({
type: "GET",
// TODO
})
但上述代碼瀏覽器跑起來一看, 會看到它會嘗試options和GET兩次, 實際你只要管GET就行了。如果你在axum的路由裡配置的是post, 但ajax請求的類型配置成get, 那無論nginx配置文档怎麽搞都會出現405。另外js的console會報錯: Access-allow-origin或者某其他跨域配置字段只允許出現一次xxx。這些都會使人迷惑。
跨域到底是哪裡引發的報錯?
這個問題是老生常談了。筆者總結,報錯的原因主要是:
1、客戶耑的請求方式和跨域對應的允許範圍不匹配。
2、服務耑方面,要麽是nginx配置文档, 要麽是後耑(rust路由)的跨域配置出現了問題; 建議nginx配置了跨域, 後耑流程能跑通就別動, 否則就撤掉nginx的跨域配置只配置後耑。
網上有的說要在ajax的請求頭裡加上xxx, 能解決問題?筆者倒是沒碰過, 估計是想多了,服務耑默認不讓跨域,客戶耑難道能擅自做主?
跨域報錯的話, axum内部的業務邏輯方法會執行嗎?
有的情況下會考慮到是不是業務邏輯影響的。實測請求會被攔截, 不存在内部業務邏輯引起的跨域問題。如果跨域配置對了,内部業務邏輯沒跑通,只會報業務邏輯的bug;