Angular2 Заголовки

Когда я вызываю сервер без заголовков, его работа и сервер возвращают json:

this.http.get(url)

но когда я добавляю заголовок:

var headers = new Headers({'x-id': '1'});
this.http.get(url, {'headers': headers})

браузер возвращает ошибку:

XMLHttpRequest cannot load http://domain/api/v1/. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access.

Я также попытался добавить Origin заголовок - ошибка браузера: Refused to set unsafe header "Origin"

И Access-Control-Allow-Origin header - без эффекта


На сервере (Laravel) я создал промежуточное ПО Cors.php:

<?php

namespace App\Http\Middleware;

use Closure;

class Cors {
    public function handle($request, Closure $next)
    {
        return $next($request)
            ->header('Access-Control-Allow-Origin', 'http://localhost:3000')
            ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
            ->header('Access-Control-Allow-Headers', 'x-id');
    }
}

Я новичок в angular2 и запросах CORS, не знаю, что делать.

  • Angular: 2.0.0-beta.0
  • Laravel: 5.0
  • Браузер: Google Chrome

Ответы

Ответ 1

Предварительно запрошенный запрос с CORS означает, что HTTP-запрос OPTIONS выполняется до фактического. Вы переключаетесь с простого запроса на тот, поскольку вы добавляете настраиваемый заголовок в случае метода GET. Эта ссылка может помочь вам понять, что происходит: http://restlet.com/blog/2015/12/15/understanding-and-using-cors/.

FYI заголовок Origin автоматически добавляется браузером при выполнении запроса кросс-домена.

Я думаю, что ваша проблема находится в заголовке Access-Control-Allow-Origin. Вы должны установить хост, который выполняет вызов, а не адрес сервера. Вы должны иметь это вместо этого (если ваше приложение Angular2 работает на localhost:8080):

return $next($request)
        ->header('Access-Control-Allow-Origin', 'http://localhost:8080')
        ->header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
        ->header('Access-Control-Allow-Headers', 'x-id');

Надеюсь, это поможет вам, Thierry

Ответ 2

У меня была такая же проблема в моем приложении Angular2. Проблема, как уже было сказано, заключается в том, что перед каждым запросом, сделанным клиентом, на сервер отправляется запрос предварительной проверки.

Этот тип запроса имеет тип OPTIONS, и он обязан отправить сервер обратно ответный сигнал перед полетом со статусом 200 и заголовками, установленными для приема запросов от этого клиента.

Это мое решение (с выражением):

// Domain you wish to allow
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');

// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');

// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'YOUR-CUSTOM-HEADERS-HERE');

// Set to true if you need the website to include cookies in  requests
res.setHeader('Access-Control-Allow-Credentials', true);

// Check if Preflight Request
if (req.method === 'OPTIONS') {
    res.status(200);
        res.end();
}
else {
    // Pass to next layer of middleware
    next();
}

Таким образом, клиент будет авторизован, и вы сможете настроить свои собственные заголовки во всех запросах. В вашем случае вам нужно установить x-id в опции Access-Control-Allow-Headers.

Ответ 3

В вашем случае сервер должен ответить на запрос перед полетом следующими заголовками:

Access-Control-Allow-Origin: *

X-Custom-HeaderAccess-Control-Allow-Methods: GET, POST, PUT, DELETE

Access-Control-Allow-Headers: x-id

Обратите внимание, что для заголовка HTTP Access-Control-Allow-Origin лучше всего установить домен, в котором приложение angular2 размещено явно, а не *, которое необходимо только для общедоступного API где вы не контролируете всех потребителей!

Я настоятельно рекомендую вам прочитать следующую статью о CORS:

http://www.html5rocks.com/en/tutorials/cors/

Ответ 4

Я разрабатывал приложение angular2 с концом c# web api и столкнулся с проблемой с настройками cors.

Реальная проблема оказалась не в настройках cors, а в том, что данные, отправляемые в api (js date object to С# datetime type, не выстроились правильно). Однако, в вашем случае, абсолютно необходимо передать x-id в заголовке, а не как параметр в запросе? Например, вы могли бы сделать что-то вроде этого:

getYourDataType(id: number): Observable<YourDataType> {
    return this.http.get(url + '/' + id.toString())
        .map((response: Response) => <YourDataType>response.json());

Из моих исследований после решения этой проблемы кажется, что angular попытается найти конечную точку, которую вы пытались ударить, не смог ее найти, а затем предположил, что причина должна быть чем-то неправильным с настройками cors, а не данные клиентской стороны.

Вы сказали, что api возвращает данные, когда вы не устанавливаете заголовки в своем запросе, поэтому, если переключение с заголовка на параметр не работает, вы можете попробовать проверить запрос с помощью инструмента, такого как скрипач или сеть вкладку инструментов chrome dev и посмотрите, построил ли angular каждый запрос, как вы ожидаете, он должен иметь. Или, сравнивая результаты, вручную создавая запрос в скрипаче, может быть очень хорошо освещено то, что именно происходит, чтобы дать вам этот неожиданный ответ.

В любом случае, выяснив, что проблема с вашими данными, а не с настройками cors, довольно сложно. angular Вы смотрите на совершенно неправильную вещь, пытающуюся выяснить очень простую проблему. Надеюсь, это поможет кому-то.

Ответ 5

проблема в том, что вам также необходимо установить разрешенные заголовки. Вот почему он не работает. Чтобы заставить его работать с простым angular2 http-запросом, вам нужно добавить следующие заголовки:

    header('Access-Control-Allow-Origin: *');
    header("Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept"); // In your case also add x-id or what you are also using. 
    header('Access-Control-Allow-Methods: POST, PUT, DELETE, GET, OPTIONS');

Ответ 6

Попробуйте использовать следующий код. Это должно работать

let headers = new Headers();
headers.append('Accept', 'application/json');
headers.append('Content-Type', 'application/json');
headers.append('x-id','1');
this.http.get(url, {'headers': headers}).subscribe(
  response => {...},
  error => {...}
);