我尝试处理 API 范围内的路由的 CORS。如果我收到 OPTION 请求,我会立即返回响应,这样应用程序就不必处理它。但是,如果我收到 GET 请求,我会添加正确的标头并将更新后的响应返回到控制器(或其他中间件,如果有的话),但在控制器中,响应对象 ($this->response) 没有之前设置的内容不再有标题了。
$routes->plugin(
'Ark',
['path' => '/ark'],
function (RouteBuilder $routes)
{
$routes->setRouteClass(DashedRoute::class);
$routes->registerMiddleware('cors', function($req, $res, $next) {
$lAllowed = [
'localhost:8081',
'localhost:8082',
'localhost:8087',
'172.16.1.225',
'172.16.1.225:8081',
'172.16.1.225:8082',
'172.16.1.225:8087',
'172.16.1.224',
];
if( $sOrigin = $req->getHeader('origin') )
{
$sOrigin = reset($sOrigin);
$sOrigin = str_replace('https://', '', $sOrigin);
$sOrigin = str_replace('http://', '', $sOrigin);
}
if( empty($sOrigin) )
$sOrigin = $req->host();
/** @var \Cake\Http\ServerRequest $req */
/** @var \Cake\Http\Response $res */
if( in_array($sOrigin, $lAllowed) )
{
//debug( 'Allow' );
$res = $res->cors($req)
->allowOrigin($req->getHeader('origin')) //only one host should be allowed when allow credentials is true
->allowMethods(['GET', 'OPTIONS'])
->allowHeaders(['Content-Type', 'X-CSRF-Token', 'Authorization'])
->allowCredentials()
->maxAge(3600) //1h
->build();
//return immediately for CORS requests
if ( strtoupper($req->getMethod()) === 'OPTIONS' )
{
return $res->withStatus(200, 'You shall pass!!');
}
//debug( $res );
}
return $next($req, $res);
});
$routes->prefix('Api', ['path' => '/api'], function(RouteBuilder $route) {
// Parse specified extensions from URLs
$route->setExtensions(['json']);
//allow external services use this api
$route->applyMiddleware('cors');
$route->prefix('V1', ['path' => '/v1'], function(RouteBuilder $route) {
// Translates to `Controller\Api\V1\` namespace
$lListOfResources = [
//Table names...
];
foreach ($lListOfResources as $sResourceName)
{
$route->resources($sResourceName, [
'map' => [
':id/restore' => ['action' => 'restore', 'method' => ['PUT', 'PATCH']],
'list' => ['action' => 'list', 'method' => 'GET'],
'filter/*' => ['action' => 'filter', 'method' => 'GET'],
]
]);
}
$route->fallbacks();
});
});
//default landing page
$routes->connect('/', ['controller' => 'Pages']);
}
);
这是一个错误还是 RoutingMiddleware 在任何控制器操作之前不能修改响应? 我应该在 Filter 之前的控制器中添加 CORS 逻辑吗?
cakephp 4.2.12 PHP 8.0.1
这是 CakePHP 4.0 的预期行为。作为参数传递给中间件的响应对象将不再像 3.x 中那样传递给控制器,该中间件语法仅出于部分向后兼容性原因而存在。
在 4.x 中,控制器默认使用新的响应对象,中间件从
$next()
调用接收它,分别是较新的 CakePHP 版本中的 $handler->handle()
调用,其中不再存在响应参数。
基本上,中间件并不意味着能够修改控制器理论上可以接收的响应对象,它们意味着返回自定义响应对象以尽早退出,或者可能修改从处理程序接收到的响应对象,这可以是从控制器层返回的响应,或从另一个中间件返回的响应。
如果您想从中间件将任何类型的数据传递到控制器层,那么您应该将其传递到请求对象中。
另请参阅