'true', 'Access-Control-Max-Age' => '1800', 'Access-Control-Allow-Methods' => '*', 'Access-Control-Allow-Headers' => '*', ]; /** * 根据 Origin 与配置写入 Access-Control-Allow-Origin。 * 注意:* 与 Access-Control-Allow-Credentials:true 不能同时出现,故通配时去掉 Credentials。 */ private static function applyCorsOrigin(Request $request, array $header): array { $origin = $request->header('origin'); if (is_array($origin)) { $origin = $origin[0] ?? ''; } $origin = is_string($origin) ? trim($origin) : ''; $corsDomain = array_map('trim', explode(',', config('buildadmin.cors_request_domain', ''))); $corsDomain[] = $request->host(true); $wildcard = in_array('*', $corsDomain); if ($origin !== '') { $info = parse_url($origin); $host = ''; if (is_array($info)) { $host = $info['host'] ?? ''; } $allowed = $wildcard || in_array($origin, $corsDomain) || in_array($host, $corsDomain) || ($host === 'localhost' || $host === '127.0.0.1'); if ($allowed) { $header['Access-Control-Allow-Origin'] = $origin; } return $header; } if ($wildcard) { $header['Access-Control-Allow-Origin'] = '*'; unset($header['Access-Control-Allow-Credentials']); } return $header; } /** * 返回 CORS 预检(OPTIONS)响应,供路由直接调用(Webman 未匹配路由时不走中间件) */ public static function optionsResponse(Request $request): Response { $header = [ 'Access-Control-Allow-Credentials' => 'true', 'Access-Control-Max-Age' => '1800', 'Access-Control-Allow-Methods' => 'GET, POST, PUT, DELETE, PATCH, OPTIONS', 'Access-Control-Allow-Headers' => 'Content-Type, Authorization, batoken, ba-user-token, think-lang', ]; $header = self::applyCorsOrigin($request, $header); return response('', 204, $header); } public function process(Request $request, callable $handler): Response { $path = trim($request->path(), '/'); if (!str_starts_with($path, 'api/') && !str_starts_with($path, 'admin/')) { return $handler($request); } $header = self::applyCorsOrigin($request, $this->header); if ($request->method() === 'OPTIONS') { return response('', 204, $header); } $response = $handler($request); return $response->withHeaders($header); } }