Patch: https://github.com/spyrr/rocket-backend-ex/commit/f91cdec4fbddac711e46aec06a8444de9f5c1208
지난번에 rocket으로 만든 백엔드에 vue 프론트를 붙여, 실행해보면, CORS와 관련하여 console error를 보여주면서, 정상적인 동작을 하지 않는다.
혹시나 해서... Rocket::shield [1] 의 내용을 확인했으나, CORS에 대한 설정은 지원하지 않는 것 같다.
이에.. 아래[2]와 같이 패치를 작성해서 1차적으로 테스트를 진행했다.
* CORS 설정 상 보안 요소는... 고려하지 않았다. 나중에 여러 가지로 테스트 해보려 함 -_-;
main.rs 파일 내, 추가한 CORS 관련 설정 내용 [2]
// for CORS settings
use rocket::{Request, Response};
use rocket::fairing::{Fairing, Info, Kind};
use rocket::http::Header;
pub struct CORS;
#[rocket::async_trait]
impl Fairing for CORS {
fn info(&self) -> Info {
Info {
name: "Add CORS headers to responses",
kind: Kind::Response,
}
}
async fn on_response<'r>(&self, request: &'r Request<'_>, response: &mut Response<'r>) {
response.set_header(Header::new("Access-Control-Allow-Origin", "*"));
response.set_header(Header::new("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE"));
response.set_header(Header::new("Access-Control-Allow-Headers", "*"));
response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
}
}
CORS를 사용하도록 설정 [2]
rocket::build()
.attach(CORS)
.manage(db)
.mount("/health", routes![check_health])
.mount("/api/v1/books", routes![
routes::books::get_books, // get
routes::books::get_book, // get
routes::books::new_book, // post
routes::books::update_book, // put
routes::books::delete_book,// delete
]).launch().await
그러나, 결과는... OPTIONS 메소드로 요청하는 preflight 결과가 404 에러를 뱉어내자, 기능이 정상적으로 동작하지 않았다. 이것 때문에, CORS 설정이 잘못된 줄 알고 이짓 저짓하느라 시간 낭비를....
결과적으로 OPTIONS 요청에 대해 200 OK 응답을 하면... 정상적으로 실행되었다.
Rocket 의 Faring Hook을 통해, 모든 OPTIONS 요청에 대해 200 OK 204 No Content로 응답하도록 코드 작성
// for CORS settings
use rocket::{Request, Response};
use rocket::fairing::{Fairing, Info, Kind};
-use rocket::http::Header;
+use rocket::http::{Header, Status, Method};
+use rocket::yansi::Paint;
+use std::io::Cursor;
pub struct CORS;
#[rocket::async_trait]
impl Fairing for CORS {
fn info(&self) -> Info {
Info {
name: "Add CORS headers to responses",
kind: Kind::Response,
}
}
async fn on_response<'r>(&self, request: &'r Request<'_>, response: &mut Response<'r>) {
response.set_header(Header::new("Access-Control-Allow-Origin", "*"));
response.set_header(Header::new("Access-Control-Allow-Methods", "POST, GET, PUT, DELETE"));
response.set_header(Header::new("Access-Control-Allow-Headers", "*"));
response.set_header(Header::new("Access-Control-Allow-Credentials", "true"));
+ // For preflight
+ if request.method() == Method::Options {
+ info_!("{}", Paint::green("Maybe preflight?"));
+ let rv = "";
+ response.set_status(Status::NoContent);
+ response.set_sized_body(rv.len(), Cursor::new(rv));
+ }
}
}
처음엔... 모든 routes 에 대해 options 함수를 등록해서 사용했으나, 매우 비효율 적인데다, options 함수에서는 특별히 하는 일도 없기에... 위에처럼 로켓의 후커에서 response 명령에 대해 options 요청이 오면 무조건 200 ok를 뱉어내도록 강제했다.
아마도.... CORS와 더불어... preflight에 대해서도 공부가 필요할 것 같다. 저게 왜 필요한지도...
참고자료
[2] http - How to set up CORS or OPTIONS for Rocket.rs - Stack Overflow
[3] rocket_cors - Rust (docs.rs)