1. In Yii2, when a server-side exception occurs, it does not return a 500 response. Instead, the browser reports a CORS error, which causes the frontend to hang in a loading state from the user’s perspective. The console displays the following message, as shown in Figure 1.

Access to XMLHttpRequest at 'https://api.apply.local/convention-free-field/get-search-condition-fields-by-convention-id' from origin 'https://console.apply.local' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values 'https://console.apply.local, *', but only one is allowed.
2. The current logic is that in the browser, the frontend requests the backend API via JS. Therefore, to prevent CORS issues, the backend implementation is as follows.
public static function setAllowOrigin()
{
$httpOrigin = $_SERVER['HTTP_ORIGIN'] ?? '';
Yii::debug('OPTION CHECK: ' . $httpOrigin);
if (
in_array($httpOrigin, [
//
'http://console.apply.local',
'https://console.apply.local',
'http://tougao.apply.local',
'https://tougao.apply.local',
'http://apply.local',
'https://apply.local',
'http://official.local',
'http://localhost:8080',
'http://localhost:8081',
'http://localhost:8082',
'http://localhost:8083',
'http://localhost:8084',
//正式域名
])
) {
\Yii::$app->response->headers->add('Access-Control-Allow-Origin', $httpOrigin);
\Yii::$app->response->headers->add('Access-Control-Allow-Headers', '*');
}
}
self::setAllowOrigin();
3. A close analysis of the request response headers reveals that access-control-allow-origin: * overrides the access-control-allow-origin: https://console.apply.local set in the setAllowOrigin method. As shown in Figure 2.

4. I decided to comment out all instances of the setAllowOrigin method from step 2 to avoid leaving a large number of commented-out self::setAllowOrigin(); calls.
public static function setAllowOrigin()
{
// $httpOrigin = $_SERVER['HTTP_ORIGIN'] ?? '';
// Yii::debug('OPTION CHECK: ' . $httpOrigin);
// if (
// in_array($httpOrigin, [
// //
// 'http://console.apply.local',
// 'https://console.apply.local',
// 'http://tougao.apply.local',
// 'https://tougao.apply.local',
// 'http://apply.local',
// 'https://apply.local',
// 'http://official.local',
// 'http://localhost:8080',
// 'http://localhost:8081',
// 'http://localhost:8082',
// 'http://localhost:8083',
// 'http://localhost:8084',
// //正式域名
// ])
// ) {
// \Yii::$app->response->headers->add('Access-Control-Allow-Origin', $httpOrigin);
// \Yii::$app->response->headers->add('Access-Control-Allow-Headers', '*');
// }
}
self::setAllowOrigin();
5. Centralize the configuration in the base class of all API controllers.
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['corsFilter'] = [
'class' => Cors::class,
'cors' => [
'Origin' => [
//
'http://console.apply.local',
'https://console.apply.local',
'http://tougao.apply.local',
'https://tougao.apply.local',
'http://apply.local',
'https://apply.local',
'http://official.local',
'http://localhost:8080',
'http://localhost:8081',
'http://localhost:8082',
'http://localhost:8083',
'http://localhost:8084',
//正式域名
],
'Access-Control-Allow-Headers' => ['*'],
],
];
return $behaviors;
}
6. When a server-side exception occurs, the browser no longer reports a CORS error. Instead, it responds normally as expected. As shown in Figure 3.

7. Checking the response headers shows access-control-allow-origin: https://console.apply.local. This matches expectations. As shown in Figure 4.

8. When the frontend URL is not in the Origin configuration, it reports a CORS error, which is the expected behavior.
Access to XMLHttpRequest at 'https://api.apply.local/convention-free-field/get-search-condition-fields-by-convention-id' from origin 'https://console.apply.local' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
