Open ysysimon opened 1 month ago
Would you like to paste your code here?
Task<HttpResponsePtr> CORSMiddleware::invoke(const HttpRequestPtr &req, MiddlewareNextAwaiter &&next)
{
const std::string& origin = req->getHeader("Origin");
// 检查是否允许所有来源 (通配符 *)
bool allowAllOrigins = (allowedOrigins_.find("*") != allowedOrigins_.end());
spdlog::info("被调用!!!");
// 处理 OPTIONS 预检请求
if (req->method() == Options)
{
spdlog::info("CORSMiddleware invoked by {} 跨域中间件被调用", origin);
// 检查 Origin 是否被允许
if (!allowAllOrigins && allowedOrigins_.find(origin) == allowedOrigins_.end())
{
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k403Forbidden);
resp->setBody("403 Forbidden - Origin not allowed 非法跨域请求");
mcb(resp); // 返回响应,终止进一步处理
spdlog::warn("Origin {} not allowed, 403 Forbidden 非法跨域请求", origin);
return;
}
// 返回预检请求响应
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k200OK);
if (allowAllOrigins)
{
resp->addHeader("Access-Control-Allow-Origin", "*");
}
else
{
resp->addHeader("Access-Control-Allow-Origin", origin);
}
resp->addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
resp->addHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
resp->addHeader("Access-Control-Allow-Credentials", "true");
mcb(resp); // 返回响应,终止进一步处理
return;
}
or Coroutine version
Task<HttpResponsePtr> CORSMiddleware::invoke(const HttpRequestPtr &req, MiddlewareNextAwaiter &&next)
{
const std::string& origin = req->getHeader("Origin");
// 检查是否允许所有来源 (通配符 *)
bool allowAllOrigins = (allowedOrigins_.find("*") != allowedOrigins_.end());
spdlog::info("被调用!!!");
// 处理 OPTIONS 预检请求
if (req->method() == Options)
{
spdlog::info("CORSMiddleware invoked by {} 跨域中间件被调用", origin);
// 检查 Origin 是否被允许
if (!allowAllOrigins && allowedOrigins_.find(origin) == allowedOrigins_.end())
{
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k403Forbidden);
resp->setBody("403 Forbidden - Origin not allowed 非法跨域请求");
spdlog::warn("Origin {} not allowed, 403 Forbidden 非法跨域请求", origin);
co_return resp; // 返回响应,终止进一步处理
}
// 返回预检请求响应
auto resp = HttpResponse::newHttpResponse();
resp->setStatusCode(k200OK);
if (allowAllOrigins)
{
resp->addHeader("Access-Control-Allow-Origin", "*");
}
else
{
resp->addHeader("Access-Control-Allow-Origin", origin);
}
resp->addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS");
resp->addHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
resp->addHeader("Access-Control-Allow-Credentials", "true");
co_return resp; // 返回响应,终止进一步处理
}
// 继续处理普通请求,等待下一个中间件或控制器
auto resp = co_await next; // 继续请求处理
spdlog::info("普通请求");
// 在响应中添加 CORS 头
if (allowAllOrigins)
{
resp->addHeader("Access-Control-Allow-Origin", "*");
}
else
{
resp->addHeader("Access-Control-Allow-Origin", origin);
}
resp->addHeader("Access-Control-Allow-Credentials", "true");
co_return resp; // 返回最终的响应
}
header file is like
class CORSMiddleware : public drogon::HttpCoroMiddleware<CORSMiddleware>
{
public:
static constexpr bool isAutoCreation = false; // 明确设置为 false
CORSMiddleware(const std::unordered_set<std::string>& allowedOrigins);
Task<HttpResponsePtr> invoke(const HttpRequestPtr &req,
MiddlewareNextAwaiter &&next) override;
private:
std::unordered_set<std::string> allowedOrigins_;
};
and I try to register it this way
auto corsMiddleware = std::make_shared<YLineServer::CORSMiddleware>(config.allowed_origins);
drogon::app().registerMiddleware(corsMiddleware);
// 将协程中间件注册为 Pre-Routing Advice
// 注册 Pre-Routing Advice
drogon::app().registerPreRoutingAdvice([corsMiddleware](const HttpRequestPtr &req, AdviceCallback &&callback, AdviceChainCallback &&chainCallback) {
// 调用中间件的 invoke 方法
corsMiddleware->invoke(req,
// nextCb:继续执行下一个中间件或控制器的回调
[chainCallback = std::move(chainCallback)](const std::function<void(const HttpResponsePtr &)>& nextResponseCb) {
// 执行下一个 Pre-Routing Advice 或进入路由处理
chainCallback();
},
// mcb:终止请求并返回响应的回调
[callback = std::move(callback)](const HttpResponsePtr &resp) {
// 返回响应
callback(resp);
}
);
When I use HttpCoroMiddleware, the middleware cannot be used. I don't know the correct way to manually register it (via registerPreRoutingAdvice). Even if register it through the ADD_PATH_TO macro, it can't work correctly. When I use HttpMiddleware, the Option request can be completed normally, but subsequent POST and other requests still cannot add the correct "Access-Control-Allow" request header information. 当我使用 HttpCoroMiddleware ,中间件无法使用,我不知道手动注册它的正确方法 (通过 registerPreRoutingAdvice),即使通过 ADD_PATH_TO 宏通过了编译,也无法正确工作,而当我使用 HttpMiddleware,Option 请求可以正常完成,但是后续的 POST 等请求仍然无法 添加正确的 “Access-Control-Allow” 请求头信息
Middleware in drogon is not global, after registering your middleware to framework, did you add the name of middleware to your routing path in controllers?
Middleware in drogon is not global, after registering your middleware to framework, did you add the name of middleware to your routing path in controllers?
yes, I tried both ‘registerPreRoutingAdvice’ and ADD_PATH_TO
option requests do not enter middlewares or handlers. They are handled directly by framework during routing.
not all true, I'll look into it later.
According to my test, option request is not automatically handled by the framework, I have to add middleware to handle it. The situation as follows:
drogon::app().registerPreRoutingAdvice
to add the route of it as a global middleware
nextCb([origin, mcb = std::move(mcb), allowAllOrigins](const HttpResponsePtr& resp) mutable {
spdlog::info("normal request");
// Add CORS header to the response
if (allowAllOrigins)
{
resp->addHeader("Access-Control-Allow-Origin", "*");
}
else
{
resp->addHeader("Access-Control-Allow-Origin", origin);
}
resp->addHeader("Access-Control-Allow-Credentials", "true");
mcb(resp); // Return the final response
});
Task<HttpResponsePtr> CORSMiddleware::invoke(const HttpRequestPtr &req, MiddlewareNextAwaiter &&next)
{
const std::string& origin = req->getHeader("Origin");
// Check if all origins are allowed (wildcard *)
bool allowAllOrigins = (allowedOrigins_.find("*") != allowedOrigins_.end());
spdlog::info("Called!!!");
// Handle OPTIONS pre-check request if (req->method() == Options) { spdlog::info("CORSMiddleware invoked by {} Cross-origin middleware is called", origin);
// Check if Origin is allowed if (!allowAllOrigins && allowedOrigins.find(origin) == allowedOrigins.end()) { auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k403Forbidden); resp->setBody("403 Forbidden - Origin not allowed Illegal cross-domain request"); spdlog::warn("Origin {} not allowed, 403 Forbidden Illegal cross-domain request", origin); co_return resp; // Return response and terminate further processing }
// Return pre-check request response auto resp = HttpResponse::newHttpResponse(); resp->setStatusCode(k200OK); if (allowAllOrigins) { resp->addHeader("Access-Control-Allow-Origin", "*"); } else { resp->addHeader("Access-Control-Allow-Origin", origin); } resp->addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS"); resp->addHeader("Access-Control-Allow-Headers", "Content-Type, Authorization"); resp->addHeader("Access-Control-Allow-Credentials", "true");
co_return resp; // Return response and terminate further processing }
// Continue processing normal requests and wait for the next middleware or controller auto resp = co_await next; // Continue request processing
spdlog::info("Normal request");
// Add CORS header to the response if (allowAllOrigins) { resp->addHeader("Access-Control-Allow-Origin", "*"); } else { resp->addHeader("Access-Control-Allow-Origin", origin); } resp->addHeader("Access-Control-Allow-Credentials", "true");
co_return resp; // Return the final response }
But this time I don't know how to use
```cpp
drogon::app().registerPreRoutingAdvice
to add the route of this coroutine middleware, so I manually added it in the ADD_PATH_TO macro of the controller, but this time even the Option request was not handled correctly
Ok, I seem to have misunderstood it, I thought the generated response would also go through the middleware to be add CORS header
I am confused, only request will go through the middleware and not respond?
It seems that the fact is that only the option request goes through the full onion ring, while the subsequent post request, etc., only the request enters, but the respond does not. It is directly returned to the client, resulting in no corresponding response header information being added.
I'm trying to use a CROS middleware with my coroutine controller, but no matter what I try, the options request goes through fine, but subsequent requests still lack the Access-Control-Allow request header. I've tried using both HttpCoroMiddleware and HttpMiddleware