选项预检导致 POST 请求挂起

OPTIONS Preflight causing POST request to hang

我的 angular 应用程序的 CORS OPTIONS 预检请求一直存在问题。简而言之,我正在尝试实现一个简单的登录,它向我的服务器发送一个 POST 请求,该服务器有一个使用 PHP\Slim 构建的后端,携带用户的凭据。 CORS OPTIONS 首先请求,我用 slim 处理它以响应 200 OK,所以当浏览器获得 OK 时它最终发送我的 POST 和凭据,但它只是挂起......没有响应代码,没什么。

老实说,这让我很困惑,我真的在猜测我的请求服务有问题,因为这是唯一发送 OPTIONS 请求的服务。

疯狂的是,在我向登录按钮发送垃圾邮件后,它最终屈服并做出回应。

I checked the network requests and this is the idea of what it looks like:

200 OPTIONS
    POST
200 OPTIONS
    POST

the posts are just blank

这是我的服务。

  signin(user: User): Observable<Result> {
    return this._http.post<Result>( this.base + this.signinURL, user )
      .pipe(catchError(this.error));
  }

  private error(error: HttpErrorResponse) {
    return throwError(error);
  }

这是 CORS 相关的路由

$app->options('/{routes:.+}', function (Request $request, Response $response, $args) {
    return $response->withStatus(200);
});
$app->add(function (Request $req, Response $res, $next) {
    $response = $next($req, $res);
    return $response
        ->withHeader('Access-Control-Allow-Origin', 'http://localhost:4200')
        ->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
        ->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
});
$app->map(['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], '/{routes:.+}', function(Request $req, Response $res) {
    $handler = $this->notFoundHandler;
    return $handler($req, $res);
});

另外值得一提的是,我是 运行 Angular CLI 服务器的前端和 PHP PHP 服务器 v7.3 的前端。

如果有人能向我解释发生了什么以及为什么我会高兴,谢谢你的想法...:)

客户端(浏览器)是发送 OPTIONS 请求的;这是在每次请求之前由浏览器自动完成的。一个 OPTIONS 请求只是告诉客户端允许发出什么样的请求(POST、GET、DELETE 等)。请注意,我假设您的应用程序是 web-application,因为您的代码没有展示任何明确的 OPTIONS 请求。

至于您在Chrome中没有看到POSTbody的原因,与您的服务问题无关。这是一个 chrome 特定的东西;它基本上与 refreshes/redirects 页面有关 --- Chrome 不会保留 post body。如果您保留 chrome 日志,并在任何 reload/refresh/redirect 发生之前停止网络,您将看到 body。发生这种情况有一个特定的原因,我只是不记得我在哪里读过它。我的建议是改为在本地记录。

至于您的 API,您的 OPTIONS 处理看起来有点滑稽。 $app->options 是您捕获所有 OPTIONS 请求的地方,您所做的只是返回 200;你没有定义你的 headers。未经测试,我假设这是您的问题。

我会说放弃所有这些,而只是做这样的事情:

$app = new \Slim\App();

$app->add(function (Request $request, Response $response, $next) {
    if($request->getMethod() !== 'OPTIONS') {
        return $next($request, $response);
    }

    $response = $response->withHeader('Access-Control-Allow-Origin', '*');
    $response = $response->withHeader('Access-Control-Allow-Methods', $request->getHeaderLine('Access-Control-Request-Method'));
    $response = $response->withHeader('Access-Control-Allow-Headers', $request->getHeaderLine('Access-Control-Request-Headers'));

    return $next($request, $response);
});

# ... all your other routes ...

$app->run();

或者,为什么不让您的 HTTP 服务器自己处理 OPTIONS 请求?

就我而言,我会注意到我也是 运行 一个基于 API 的 Slim PHP 7.3,我不会费心处理 OPTIONS 请求,我只需在我的虚拟主机配置 (apache2) 中设置 headers。像这样:

<VirtualHost *:443>

    ...

    <IfModule mod_headers.c>
            # allowable request origins
            Header set Access-Control-Allow-Origin "*"

            # allowable request types
            Header set Access-Control-Allow-Methods "POST, GET, DELETE, OPTIONS"

            # how long to cache results of preflight requests
            Header set Access-Control-Max-Age "1800"

            # allowable headers
            Header set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept"

            # permit preflight response requests using credentials
            Header set Access-Control-Allow-Credentials "true"
    </IfModule>

    ...

</VirtualHost>