写了半天在本地跑的好好的, 结果上不了线可就糗大了。
笔者刚开始使用的是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;