当時の状況
フロントサイドからjson形式のデータが入ったPOSTリクエストをdrogonが受け取り、処理の結果をフロントサイドに返す部分をつくっていたところです。
drogonふれーむわーくの情報はあんまり見られないのでここにまとめてみます。間違ってたらごめんなさい。
環境
バックエンド開発言語 :c++(drogon)
※HttpControllerで制御してます
座談編
CORSについて
異なるドメイン間での通信を制限するやつですね。
筆者は毎度のごとくCORSの作業で足踏みしています。
「ヘッダーに許可を書けば良いんでしょ?今回は流石に大丈夫や!」と思っていたらPreflight requesの罠にハマりました。
Preflight request
Preflight requesthは本体のhttp requestを飛ばす前に、ファイルを送っても良いのかサーバー側に確認するための通信らしいです。
Preflight requesthは送る内容によっては必要とされない場合もありますが、必要な場合はブラウザが自動で飛ばす仕組みになってるらしいです。
そして今回、 "application/json" を送信する際にはPreflight requestが飛ばされます。
しかし、drogon側は自動で処理してくれないため、自分で対応を作る必要があります。
解決編
Preflight requestに対応する
★まず、Preflight requestのメソッドは「OPTIONS」です。
→コントローラーにて、本命の通信(筆者ならPOST)に対するメソッドと同じURLにて、OPTIONSの通信に対処する関数を用意します。
↓のプログラムでは、通信メソッドがOptionならpreFlight関数へ繋ぐようになります
#pragma once
#include <drogon/HttpController.h>
using namespace drogon;
class Journing : public drogon::HttpController<Journing>
{
public:
METHOD_LIST_BEGIN
METHOD_ADD(Journing::preFlight,"/insJ/",Options);
METHOD_ADD(Journing::insertJourning,"/insJ/",Post);
METHOD_LIST_END
void preFlight(const HttpRequestPtr &req,std::function<void (const HttpResponsePtr &)> &&callback );
void insertJourning(const HttpRequestPtr &req,std::function<void (const HttpResponsePtr &)> &&callback);
};
その後、ccファイルにてアクセスを許可するヘッダを書きます。
drogon::HttpResponsePtrのaddHeader()を使用し、↓のように書きます。
#include "Journing.h"
void Journing::preFlight(const HttpRequestPtr &req,
std::function<void (const HttpResponsePtr &)> &&callback){
LOG_DEBUG<<"preflightReq :";
drogon::HttpResponsePtr resp;
header::setCommonHeader(resp);
resp->addHeader("Access-Control-Allow-Origin", "http://localhost:3000");
resp->addHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
resp->addHeader("Access-Control-Allow-Headers", "X-PINGOTHER,Content-Type");
//右側の値は用途に応じて変えてください
callback(resp);
}
void Journing::insertJourning(const HttpRequestPtr &req,
//POSTのときの処理は関係ないので省略
汎用的にCORS対策のヘッダを使いたい
さきほどのコードはPreflight requestの対応なので、本命の関数でも同じようにヘッダを追加しないと本命の通信でCORS違反になります💦
とはいえ、すべての関数に同じヘッダを付けるのは癪なので簡易的に関数としてわけました。
※.hファイルにまとめる雑さで申し訳ない。。
#pragma once
namespace header
{
void setCommonHeader(drogon::HttpResponsePtr &resp){
resp->addHeader("Access-Control-Allow-Origin", "http://localhost:3000");
resp->addHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
resp->addHeader("Access-Control-Allow-Headers", "X-PINGOTHER,Content-Type");
}
}
#include "Journing.h"
#include "commonHeader.h"
void Journing::preFlight(const HttpRequestPtr &req,
std::function<void (const HttpResponsePtr &)> &&callback){
LOG_DEBUG<<"preflightReq :";
drogon::HttpResponsePtr resp;
header::setCommonHeader(resp);
callback(resp);
}
void Journing::insertJourning(const HttpRequestPtr &req,
std::function<void (const HttpResponsePtr &)> &&callback)
{
std::shared_ptr<Json::Value> receive = req->getJsonObject();
Json::Value con;
Json::Value out;
con = *receive;
//↑ついでにJSONファイルの受け取り方も残しておく
/*処理*/
auto resp=HttpResponse::newHttpJsonResponse(out);
header::setCommonHeader(resp);
callback(resp);
}
以上。もっと良い方法が見つかったら修正するかも