ОПЦИИ Preflight вызывает зависание POST-запроса - PullRequest
0 голосов
/ 23 апреля 2019

У меня возникли проблемы с предварительным запросом 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 Server v7.3.

Если кто-то может просто объяснить мне, что происходит и почему я 'буду счастлив, спасибо за мысли ...:)

1 Ответ

1 голос
/ 23 апреля 2019

Клиент (браузер) - это то, что отправляет запрос OPTIONS; это делается автоматически браузером перед каждым запросом. Запрос OPTIONS просто сообщает клиенту, какой запрос ему разрешено делать (POST, GET, DELETE и т. Д.). Обратите внимание, что я предполагаю, что ваше приложение является веб-приложением, поскольку ваш код не демонстрирует какого-либо явного запроса OPTIONS.

Что касается причины, по которой вы не видите тело POST в Chrome, это не связано с вашими проблемами обслуживания. Это особенность хрома; это в основном связано с обновлением / перенаправлением страницы --- Chrome не будет сохранять тело сообщения. Если вы сохраните журнал Chrome и остановите сеть до того, как произойдет перезагрузка / обновление / перенаправление, вы увидите тело. Это происходит по определенной причине, я просто не могу вспомнить, где я это читал. Мой совет - просто зарегистрировать это локально.

Что касается вашего API, ваша обработка OPTIONS выглядит немного забавно. $app->options - это то место, где вы перехватываете все OPTIONS-запросы, и все, что вы делаете, возвращает 200; Вы не определяете свои заголовки. Без тестирования, я предполагаю, что это ваша проблема.

Я бы сказал, бросьте все это, и вместо этого просто сделайте что-то вроде этого:

$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?

В моем случае, который я отмечу, я также использую Slim API в PHP 7.3, я не беспокоюсь об обработке запроса OPTIONS, я просто устанавливаю заголовки в моей конфигурации виртуального хоста (apache2). Примерно так:

<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>
...