Angular2 Headers

15

在没有请求头的情况下调用服务器,它可以工作并返回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头部 - 浏览器错误:拒绝设置不安全的头部"Origin"

Access-Control-Allow-Origin头部 - 没有效果


在服务器(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

我认为这个问题在服务器属性中,请参见: https://dev59.com/2Zbfa4cB1Zd3GeqPtGaN - Emir Mamashov
6个回答

7
一个带有CORS的预检请求意味着在实际请求之前会执行OPTIONS HTTP请求。当你在GET方法中添加自定义头时,你从简单的请求转换到了复杂请求。这个链接可以帮助你理解发生了什么:http://restlet.com/blog/2015/12/15/understanding-and-using-cors/
请注意,浏览器在执行跨域请求时会自动添加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

我的客户端运行在 http://localhost:3000/,API 服务器运行在 http://DOMAIN/api/v1/ ... 当我添加请求头时,它从简单请求变成了预检请求,这不起作用并返回问题中提到的错误。 - Shaddow
1
事实上,Access-Control-Allow-Origin报头的内容可以是*。如果您只想允许CORS方面与您的应用程序有关的内容,只需从请求的Origin报头返回所获得的内容即可... - Thierry Templier

6

在我的Angular2应用程序中遇到了相同的问题。

问题如前所述,即在客户端发出每个请求之前都会发送一个预检请求到服务器。

这种类型的请求具有选项类型,并且服务器有责任发送一个预检响应,其中状态为200,并设置为接受来自该客户端的请求的标头。

这是我的解决方案(使用express):

// 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();
}

这样,客户端将被授权并且您将能够在所有请求中设置自定义标头。对于您的情况,您需要在Access-Control-Allow-Headers选项中设置x-id


1
我一直在开发一个带有C# Web API后端的Angular2应用程序,并遇到了与CORS设置相关的问题。实际问题并非CORS设置,而是发送到API的数据(JS日期对象与C#日期时间类型不对齐)。但是,在您的情况下,是否绝对必要将x-id作为标头传递,而不是作为请求参数?例如,您可以像这样做:
getYourDataType(id: number): Observable<YourDataType> {
    return this.http.get(url + '/' + id.toString())
        .map((response: Response) => <YourDataType>response.json());

经过我的研究,处理这个问题后,似乎 angular 会尝试找到你试图访问的端点,无法找到它,然后假设原因必须是跨域设置出了问题,而不是客户端数据。

你说当你在请求中没有设置任何头信息时,API会返回数据,因此,如果从头信息更改为参数不起作用,你可以尝试使用像 Fiddler 或 Chrome 开发工具的网络选项卡来检查请求,并查看 Angular 是否按照你期望的方式构造了每个请求。或者通过在 Fiddler 中手动构造请求来比较结果,这可能非常有启示性,以了解到底发生了什么,导致你得到这个意外的响应。

无论如何,弄清楚问题是出在数据上,而不是 cors 设置上相当困难。 Angular 让你看着完全错误的东西,试图解决一个非常简单的问题。我希望这能帮助某些人。


1
在您的情况下,服务器必须使用以下标头响应预检请求:

Access-Control-Allow-Origin: *

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

Access-Control-Allow-Headers: x-id

请注意,对于Access-Control-Allow-Origin HTTP标头,最佳实践是明确设置托管angular2应用程序的域,而不是*,此操作仅适用于您无法控制所有消费者的公共API!
我强烈建议您阅读有关CORS的以下文章:

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


0
问题在于您还需要设置允许的标头。这就是为什么它不起作用的原因。要使其与简单的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');

0

尝试以下代码,这应该可以工作

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 => {...}
);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接