使用CORS获取帖子问题而不是获取标题

时间:2017-03-01 22:42:16

标签: reactjs iis cors fetch

这个CORS再次让我跪倒在地。我的意思是它可以令人沮丧。在你投票给我之前,请理解我一直关注这个主题的所有500万个帖子。我意识到这个主题有很多。这是我的React UI代码中的Fetch Post。这是在带有已编译JS的IIS服务器上运行的,而且只是用于SPA的Index.html。我试图在同一服务器上调用API不同的端口。这是在Chrome和其他现代浏览器中杀死我的预检(在IE中似乎很好)。

这是获取:

    return (
        fetch(mypost, {
            method: 'POST',
            headers: {
                "Content-Type": "application/json",
                "Access-Control-Allow-Origin": "*",
                "Accept": "application/json",
            },
            mode: 'cors',
            body: JSON.stringify({
                name: this.state.value,
            })
        }).then(response => {
            if (response.status >= 400) {
                this.setState({
                    value: 'no greeting - status > 400'
                });
                throw new Error('no greeting - throw');
            }
            return response.text()
        }).then(data => {
            var myData = JSON.parse(data);
            this.setState({
                greeting: myData.name,
                path: myData.link
            });
        }).catch(() => {
            this.setState({
                value: 'no greeting - cb catch'
            })
        })
    );

标准的预见错误我们都看到了。

Fetch API无法加载http://myApiServer:81/values/dui/。对预检请求的响应没有通过访问控制检查:否'访问控制 - 允许 - 来源'标头出现在请求的资源上。起源' http://localhost:82'因此不允许访问。如果不透明的回复符合您的需求,请将请求的模式设置为“无人”状态。获取CORS禁用的资源。

这是预检的小提琴:

OPTIONS http://myApiServer:81/values/dui/ HTTP/1.1
Host: myApiServer:81
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:82
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Access-Control-Request-Headers: access-control-allow-origin, content-type
Accept: */*
Referer: http://localhost:82/validator
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

现在我已经了解到设置no-cors基本上会设置一个默认标头,这也不是我想要的,我需要我的应用程序/ json,因为谁不想要JSON,对吧? :)

我很想知道如何解决这个问题。基本上,因为这只是编译Javascript和index.html坐在IIS服务器上,我需要知道处理这些似乎正在发生的预检选项检查的最佳解决方案。

******更新

我尝试添加webconfig以强制IIS服务器处理预检。它似乎需要在两端,我的UI和API?

这是我的UI Web.Config

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
    <httpProtocol>
        <customHeaders>
            <add name="Access-Control-Allow-Origin" value="*" />
            <add name="Access-Control-Allow-Methods" value="GET,PUT,POST,DELETE,OPTIONS" />
            <add name="Access-Control-Allow-Headers" value="Content-Type" />
        </customHeaders>
    </httpProtocol>
</system.webServer>

我的WebApi web.config

  <?xml version="1.0" encoding="utf-8"?>
<configuration>

<system.webServer>
  <handlers>
    <add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
  </handlers>
  <httpProtocol>
    <customHeaders>
     <add name="Access-Control-Allow-Origin" value="*" />
     <add name="Access-Control-Allow-Headers" value="Content-Type" />
     <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE" />
    </customHeaders>
  </httpProtocol>
  <aspNetCore processPath="dotnet" arguments=".\dui.dll" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="true" />
 </system.webServer>
 </configuration>

我现在所有人都是:

fetch API无法加载http://myApiServer:81/values/dui/。预检的响应具有无效的HTTP状态代码415。

这是小提琴。

REQ

OPTIONS http://myApiServer:81/values/dui/ HTTP/1.1
Host: myApiServer:81
Connection: keep-alive
Access-Control-Request-Method: POST
Origin: http://localhost:82
User-Agent: Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Access-Control-Request-Headers: content-type
Accept: */*
Referer: http://localhost:82/validator
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

并回复

HTTP/1.1 415 Unsupported Media Type
Content-Length: 0
Server: Kestrel
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
Date: Thu, 02 Mar 2017 18:35:31 GMT

4 个答案:

答案 0 :(得分:2)

我已经为我的dotnet核心webAPi切换到这个解决方案。我发现它更干净,因为我不需要webconfig加上cors配置,需要设置正确的2才能一起工作。这消除了你的webConfig中的cors东西,所以你只能在一个地方设置它,在你的API应用程序代码本身。

https://www.codeproject.com/Articles/1150023/Enable-Cross-origin-Resource-Sharing-CORS-in-ASP-N

只是简要概述一下链接中的内容。

添加到project.json

//Cross Origin Resource Sharing
"Microsoft.AspNetCore.Cors": "1.0.0"

在启动时将此添加到您的ConfigureServices。

services.AddCors(
options => options.AddPolicy("AllowCors",
builder =>
{
    builder
    //.WithOrigins("http://localhost:4456") //AllowSpecificOrigins;
    //.WithOrigins("http://localhost:4456", 
    "http://localhost:4457") //AllowMultipleOrigins;
    .AllowAnyOrigin() //AllowAllOrigins;

    //.WithMethods("GET") //AllowSpecificMethods;
    //.WithMethods("GET", "PUT") //AllowSpecificMethods;
    //.WithMethods("GET", "PUT", "POST") //AllowSpecificMethods;
    .WithMethods("GET", "PUT", 
    "POST", "DELETE") //AllowSpecificMethods;
    //.AllowAnyMethod() //AllowAllMethods;

    //.WithHeaders("Accept", "Content-type", "Origin", "X-Custom-Header");  
    //AllowSpecificHeaders;
    .AllowAnyHeader(); //AllowAllHeaders;
})
);

还可以在启动时配置

//Enable CORS policy "AllowCors"
    app.UseCors("AllowCors");

然后在你的控制器中确保你有这些参考:

 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Cors;
 using CrossOrigin.WebService.Models.DbEntities;
 using Microsoft.EntityFrameworkCore;

最后将属性添加到控制器类中。

[EnableCors("AllowCors"), Route("api/[controller]")]
 public class ContactController : Controller

答案 1 :(得分:2)

我现在已经摸不着头脑了2个小时,最后找到了一个适合我案例的解决方案。如果你和我一样处于同样的境地,我希望我的回答可以帮助你节省这些时间。由于我可以控制Web API(aspnet core)和客户端(fetch),因此我执行了以下操作:

  • 首先, 非常了解CORS非常重要。我建议你保留15~30分钟的时间,这样可以节省你的时间,相信我。在Puerto mentioned,请阅读文档:https://docs.microsoft.com/en-us/aspnet/core/security/cors
  • 在我看来,关于CORS的Microsoft文档对我们.NET开发人员来说更容易理解。如果你愿意,你也可以阅读MDN docs,但我很难理解并把各个部分放在一起。

现在我们了解了一些关于CORS的内容,请在Startup.cs文件中执行以下操作:

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment environment)
{
    app.UseCors(builder =>
    {
        builder.WithOrigins("http://yourclient/");
        builder.AllowAnyMethod();
        builder.AllowAnyHeader();
    });

    app.UseMvc();
}

现在在客户端,执行此操作:

fetch("http://yourapi/api/someresource", {
    method: "POST",
    headers: {
        "Content-Type": "application/json",
        "Access-Control-Request-Headers": "*",
        "Access-Control-Request-Method": "*"
    },
    body: JSON.stringify(data)
})...;

就是这样。

答案 2 :(得分:2)

正如某人建议的是另一篇文章,假设您未使用Nodejs,请在服务器端执行此操作。请注意,我遇到类似问题的客户端是Reactjs驱动的,这使我们什至

app.use(函数(req,res,next){

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

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

// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

// Set to true if you need the website to include cookies in the requests sent
// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);

// Pass to next layer of middleware
next();

});

答案 3 :(得分:1)

所以我要发布这个答案,因为它现在实际上对我有用。这是我经历的。我不完全确定为什么,但我会尽力解释我在这路上学到的东西。如果有人关心纠正或进一步解释,我将很乐意给予信任和支持。

因此,似乎在API中有3层CORS认知。

第1层

API本身的代码将有一些CORS设置,你应该特别注意,你一定要仔细阅读。在我的例子中,标准位置在webApi的Startup.cs中。我总是在我的WebApi中有这些,坦率地说,我认为这是最初需要的(我知道的很少)。

services.AddCors();
app.UseCors(builder => builder.AllowAnyOrigin())

我也将它设置在我的webconfig中,它将我们带到:

第2层

<customHeaders>
    <add name="Access-Control-Allow-Origin" value="*" />
    <add name="Access-Control-Allow-Headers" value="Content-Type" />
    <add name="Access-Control-Allow-Methods" value="GET, POST, PUT, DELETE" />
</customHeaders>

我使用这个是因为一个聪明人说(感谢@sideshowbarker)我的React UI中的Fetch生成了一个自定义标题,因此在我的服务器上产生了预检响应,因此需要在服务器级别处理响应

第3层

所以第3层结果确实不是我的问题,但在这个过程中你必须要注意这一点。所以不是在API代码中,不是在服务器上,而是在UI(调用应用程序)本身。

一般来说,除了"Access-Control-Allow-Origin": "*"之外,我在这里有正确的东西,这显然在这里并不需要所有地方,因为这是响应标题,而在fetch中我指定了请求标题,再次感谢@sideshowbarker。

所以我的Fetch请求如下所示:

fetch(mypost, {
    method: 'POST',
    headers: {
        "Content-Type": "application/json"
    },
    mode: 'cors',
    body: JSON.stringify({
        name: this.state.value,
    })
})

在我的案例中,主要是因为我'context-type: application/json'导致了预检反应。我想这不标准。在我们这个世界里,对我来说似乎很标准,但我知道什么。

无论如何,尽管如此,我还是得到了以下信息,坦率地说比看到预检错误更好。进步是进步。

  

Access-Control-Allow-Origin'标头包含多个值'*,*',   但只允许一个。

我在网上发现了一些提到我在两个地方都不需要AllowAnyOrigin的东西(网络服务器和API)所以我试着评论这段代码。

//app.UseCors(builder => builder.AllowAnyOrigin());

得到了:

  

Fetch API无法加载http://ApiServer:81/values/dui/。回应   预检具有无效的HTTP状态代码415

然后根据一些搜索发现一篇文章说最后一个错误可能与标题相关。我回到API源dotnet Core cors。

https://docs.microsoft.com/en-us/aspnet/core/security/cors

这是一个很好的参考。我应该更加关注这一点。它并没有完全解决我的问题,但我注意到有另一个我可以用于标题的构建器,所以我插入,重建,发布和bam,没有更多的CORS问题。一切正常!

这是我插入API的代码:

app.UseCors(builder => builder.AllowAnyHeader());

我的所有其余代码在第2层和第3层保持不变。我将第1层API中的AllowAnyOrigin构建器留下了注释。

我很遗憾在这里过于冗长,但我发现CORS很痛苦,我希望这对某人有所帮助。我想现在是Coors的时候了,但我想我们都知道啤酒很糟糕。我想这毕竟是有道理的。