我使用ngResource在亚马逊Web服务上调用REST API得到这个错误:
XMLHttpRequest无法加载
http://server.apiurl.com: 8000 / s /登录吗? =登录facebook。应对
飞行前请求未通过门禁检查:否
'Access-Control-Allow-Origin'头出现在被请求的对象上
资源。因此,来源“http://localhost”不允许访问。
错误405
服务:
socialMarkt.factory('loginService', ['$resource', function ($resource) {
var apiAddress = "http://server.apiurl.com:8000/s/login/";
return $resource(apiAddress, {
login: "facebook",
access_token: "@access_token",
facebook_id: "@facebook_id"
}, {
getUser: {
method: 'POST'
}
});
}]);
控制器:
[...]
loginService.getUser(JSON.stringify(fbObj)),
function (data) {
console.log(data);
},
function (result) {
console.error('Error', result.status);
}
[...]
我用Chrome浏览器。为了解决这个问题,我还能做些什么?
我甚至将服务器配置为接受来自源localhost的头文件。
你遇到了CORS问题。
有几种方法可以修复或解决这个问题。
关闭CORS。例如:如何在Chrome中关闭CORS
为你的浏览器使用插件
使用代理,例如nginx。示例如何设置
完成服务器的必要设置。这与您在EC2实例上加载的web服务器有关(假设这就是您所说的“Amazon web服务”)。对于特定的服务器,可以参考启用CORS网站。
更详细地说,您试图从localhost访问api.serverurl.com。这就是跨域请求的确切定义。
通过关闭它来完成你的工作(好吧,但是如果你访问其他网站,你的安全性就差了),或者你可以使用代理,让你的浏览器认为所有的请求都来自本地主机,而实际上你有一个本地服务器,然后调用远程服务器。
所以api.serverurl.com可能变成localhost:8000/api,你的本地nginx或其他代理将发送到正确的目的地。
现在,根据大众的需求,更多的CORS信息-同样的美味!
绕过CORS正是为那些只是学习前端的人所展示的。
带有承诺的HTTP示例
在我的Apache VirtualHost配置文件中,我添加了以下几行:
Header always set Access-Control-Allow-Origin "*"
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header always set Access-Control-Max-Age "1000"
Header always set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, client-security-token"
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
JavaScript XMLHttpRequest和Fetch遵循同源策略。所以,
使用XMLHttpRequest或Fetch的web应用程序只能生成HTTP
请求到自己的域。
来源:https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
你必须从你的服务器端发送Access-Control-Allow-Origin: * HTTP报头。
如果你使用Apache作为你的HTTP服务器,那么你可以像这样把它添加到你的Apache配置文件中:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin "*"
</IfModule>
Mod_headers在Apache中默认是启用的,但是,你可能想通过运行以下命令来确保它是启用的:
a2enmod headers
在ASP。NET Core Web API,这个问题通过添加“Microsoft.AspNetCore. NET”得到了解决。Cors”(版本1.1.1),并在Startup.cs中添加以下更改。
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("AllowAllHeaders",
builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
.
.
.
}
and
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// Shows UseCors with named policy.
app.UseCors("AllowAllHeaders");
.
.
.
}
并在控制器中放入[EnableCors("AllowAllHeaders")]。
我认为在Chrome中禁用CORS不是一个好方法,因为如果你在Ionic中使用它,在移动版本中肯定会再次出现这个问题。
所以最好修改后端。
首先,在header中,需要设置-
标题(“Access-Control-Allow-Origin: *”);
header(' header set Access-Control-Allow-Headers: "Origin, X-Requested-With, Content-Type, Accept"');
如果API的行为是GET和POST,那么也设置在你的头-
if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {if
(收取($ _SERVER [' HTTP_ACCESS_CONTROL_REQUEST_METHOD ']))
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
如果收取($ _SERVER [' HTTP_ACCESS_CONTROL_REQUEST_HEADERS ']))
标题(“Access-Control-Allow-Headers:
{$ _SERVER [' HTTP_ACCESS_CONTROL_REQUEST_HEADERS ']}”);退出(0);}
说到CORS,有一些注意事项。首先,它不允许通配符*,但不要在这一点上束缚我。我在什么地方读过,现在找不到那篇文章了。
如果您正在从不同的域发出请求,则需要添加允许起源标头。
Access-Control-Allow-Origin: www.other.com
如果您正在发出影响服务器资源的请求,如POST/PUT/PATCH,并且如果MIME类型不同于以下应用程序/x-www-form-urlencoded, multipart/form-data或text/plain,浏览器将自动发出一个pre-flight OPTIONS请求,以检查服务器是否允许这样做。
所以你的API/服务器需要相应地处理这些OPTIONS请求,你需要用适当的访问控制头进行响应,http响应状态码需要是200。
标题应该是这样的,根据你的需要调整它们:
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, POST, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400
max-age报头很重要,在我的情况下,没有它就不能工作,我猜浏览器需要多长时间的“访问权限”是有效的信息。
此外,如果你正在使用application/json mime从不同的域发出POST请求,你还需要添加前面提到的allow origin头,所以它看起来像这样:
Access-Control-Allow-Origin: www.other.com
Access-Control-Allow-Methods: GET, POST, PUT, PATCH, POST, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type
Access-Control-Max-Age: 86400
当飞行前成功并获得所有需要的信息时,您的实际请求将被提出。
一般来说,无论在初始请求或预飞行请求中请求了什么Access-Control头,都应该在响应中给出,以便它能够工作。
在MDN文档中有一个很好的例子,你也应该看看Stack Overflow的帖子。
跨源资源共享(Cross-Origin Resource Sharing, CORS)是一种基于http头的机制,它允许服务器指明浏览器应该允许加载资源的任何源(域、方案或端口),而不是它自己的源
来自跨原产地资源共享(CORS)
简而言之,网络服务器会告诉你(你的浏览器)你应该信任哪些网站。
Scammysite。Bad尝试告诉浏览器向good-api-site.good发送请求
good-api-site。Good告诉浏览器它应该只信任other-good-site.good
你的浏览器说你真的不应该相信诈骗网站。Bad对good-api-site的请求。很好,CORS救了你。
如果你正在创建一个网站,你真的不关心谁与你集成。犁。在ACL中设置*。
但是,如果您正在创建一个站点,并且只允许站点X,甚至站点X、Y和Z,则使用CORS指示客户端浏览器只信任这些站点与您的站点集成。
浏览器当然可以选择忽略这一点。再次强调,CORS保护的是你的客户,而不是你。
CORS允许定义*或一个站点。这可能会限制你,但你可以通过在你的web服务器上添加一些动态配置来解决这个问题——并帮助你变得具体。
这是一个关于如何在Apache中为每个站点配置CORS的示例:
# Save the entire "Origin" header in Apache environment variable "AccessControlAllowOrigin"
# Expand the regex to match your desired "good" sites / sites you trust
SetEnvIfNoCase Origin "^https://(other-good-site\.good|one-more-good.site)$" AccessControlAllowOrigin=$0
# Assuming you server multiple sites, ensure you apply only to this specific site
<If "%{HTTP_HOST} == 'good-api-site.com'">
# Remove headers to ensure that they are explicitly set
Header unset Access-Control-Allow-Origin env=AccessControlAllowOrigin
Header unset Access-Control-Allow-Methods env=AccessControlAllowOrigin
Header unset Access-Control-Allow-Headers env=AccessControlAllowOrigin
Header unset Access-Control-Expose-Headers env=AccessControlAllowOrigin
# Add headers "always" to ensure that they are explicitly set
# The value of the "Access-Control-Allow-Origin" header will be the contents saved in the "AccessControlAllowOrigin" environment variable
Header always set Access-Control-Allow-Origin %{AccessControlAllowOrigin}e env=AccessControlAllowOrigin
# Adapt the below to your use case
Header always set Access-Control-Allow-Methods "POST, GET, OPTIONS, PUT" env=AccessControlAllowOrigin
Header always set Access-Control-Allow-Headers "X-Requested-With,Authorization" env=AccessControlAllowOrigin
Header always set Access-Control-Expose-Headers "X-Requested-With,Authorization" env=AccessControlAllowOrigin
</If>
“对飞行前请求的响应没有通过访问控制检查”正是问题所在:
在发出实际的GET请求之前,浏览器会检查服务是否为CORS正确配置。这是通过检查服务是否接受实际请求将使用的方法和头来完成的。因此,允许从不同的来源访问服务是不够的,还必须满足其他必要条件。
将报头设置为
Header always set Access-Control-Allow-Origin: www.example.com
Header always set Access-Control-Allow-Methods: GET, POST, PUT, PATCH, POST, DELETE, OPTIONS
Header always set Access-Control-Allow-Headers: Content-Type #etc...
这还不够。你必须添加一个重写规则:
RewriteEngine On
RewriteCond %{REQUEST_METHOD} OPTIONS
RewriteRule ^(.*)$ $1 [R=200,L]
飞行前的一个伟大的读响应没有HTTP ok状态。