如何让 CORS 与 ASP.Net Core Web API 服务器 Angular 2 客户端一起工作

Posted

技术标签:

【中文标题】如何让 CORS 与 ASP.Net Core Web API 服务器 Angular 2 客户端一起工作【英文标题】:How to get CORS to work with ASP.Net Core Web API server Angular 2 client 【发布时间】:2017-04-08 04:33:42 【问题描述】:

我已经阅读了我能找到的关于 ASP.NET Core 和 CORS 的所有内容,并且我相信我了解其中的大部分内容,但是如果我能让它发挥作用,我会被诅咒的。我用的是Chrome浏览器,数据如下:

预检:

General:
Request URL:http://localhost:34376/api/login
Request Method:OPTIONS
Status Code:204 No Content
Remote Address:[::1]:34376

Response Headers:
view source
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:access-control-allow-origin,content-type
Access-Control-Allow-Origin:http://localhost:3000
Date:Wed, 23 Nov 2016 03:05:00 GMT
Server:Kestrel
Vary:Origin
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?QzpcUHJvamVjdHNcbXZjXFNob3BVc1NlcnZpY2Vcc3JjXFNob3BVc1NlcnZpY2VcYXBpXGxvZ2lu?=

Request Headers:
view source
Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:access-control-allow-origin, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:localhost:34376
Origin:http://localhost:3000
Referer:http://localhost:3000/authentication
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/54.0.2840.71 Safari/537.36

帖子:

Request URL:http://localhost:34376/api/login
Request Method:POST
Status Code:500 Internal Server Error
Remote Address:[::1]:34376

Response Headers:
view source
Content-Length:0
Date:Tue, 22 Nov 2016 03:11:40 GMT
Server:Kestrel
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?QzpcUHJvamVjdHNcbXZjXFNob3BVc1NlcnZpY2Vcc3JjXFNob3BVc1NlcnZpY2VcYXBpXGxvZ2lu?=

Request Headers:
view source
Accept:*/*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8
Access-Control-Allow-Origin:true
Connection:keep-alive
Content-Length:87
Content-Type:application/json
Host:localhost:34376
Origin:http://localhost:3000
Referer:http://localhost:3000/authentication
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36

Request Payload:
view source
userName: "", email: "irv@testing.com", password: "!P@ssw0rd", rememberMe: false
   email: "irv@testing.com"
   password: "!P@ssw0rd"
   rememberMe: false
   userName:""

ASP.NET Core 代码:

public void ConfigureServices(IServiceCollection services)

    services.AddCors(options => 
        options.AddPolicy("CorsPolicy",
            builder => builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials().Build() );
    );
    // Add framework services.
    services.AddApplicationInsightsTelemetry(Configuration);

    services.AddMvc();


public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)

    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    app.UseCors("CorsPolicy");

    app.UseApplicationInsightsRequestTelemetry();

    app.UseApplicationInsightsExceptionTelemetry();

    app.UseMvc();

ASP.NET Core 控制器:

[EnableCors("CorsPolicy")]
[Produces("application/json")]
[Route("api/Authentication")]
public class AuthenticationController : Controller

    private IUnitOfWork _unitOfWork;
    public AuthenticationController(IUnitOfWork unitOfWork)
    
        _unitOfWork = unitOfWork;
    

    [HttpPost]
    [Route("/api/login")]
    public JsonResult Login([FromBody]LoginInfo loginInfo)
    
        return Json(new  id_token = _unitOfWork.Users.CreateJwt(loginInfo) );
    

这是 Angular 代码:

@Injectable()
export class AuthenticationService 
private _currentAdminMode: boolean = false;

constructor(private _http: Http, private _config: ConfigurationService) 


public login(logInfo: LoginInfo): Observable<TokenContainer> 
    var headers = new Headers();
    headers.append('Content-Type', 'application/json');

    //return an observable
    return this._http.post(this._config.hostPrefix + '/api/login', JSON.stringify(logInfo),  headers: headers )
        .map((response) => 
            return <TokenContainer>(response.json());
        );

我在浏览器控制台中得到的确切错误是:

XMLHttpRequest cannot load http://localhost:34376/api/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:3000' is therefore not allowed access. The response had HTTP status code 500.

请注意,我从 POST 请求中收到 500 错误。如果出现 CORS 问题,这似乎不是服务器会发送的错误。我认为这是另外一回事,但是,所有这些代码都在单个域中工作,现在它是 CORS,有些事情正在变得混乱。无论如何,我已经阅读了我能找到的所有内容,但没有任何效果。我在想这可能与 WebAPI 路由有关。

感谢您提供的任何帮助!

【问题讨论】:

向 API 发出请求时遇到的确切错误是什么?您确定它们与 CORS 相关吗? 我从浏览器的控制台编辑了带有确切错误的问题。不知道问题出在哪里,我不知道如何进一步调试它。我在控制器操作方法上放置了一个断点,我可以告诉你我永远不会到达那个断点。谢谢! 您可以使用 Postman 或类似应用登录吗? 我用 Postman 得到了同样的结果,我刚试过....嗯 但是这个确切的服务器代码在单个域中工作(没有 CORS)虽然它也提供网页,但现在它不是 【参考方案1】:

嗯,我花了一天时间试图弄清楚如何处理几乎相同的问题。我将尝试描述更多信息:

我使用 netcoreapp1.0,基于 IIS 上的 WebAPI 的 RESTful 服务。前端:angular2。

在我的 Startup.cs 中:

// this is not much important, you can organize builder in Configure method, calling app.UseCors()
public void ConfigureServices(IServiceCollection services)
   
    services.AddCors(options =>
            
                options.AddPolicy("AllowSpecificOrigin",
                    builder => builder.WithOrigins("http://localhost:37885")
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
            );
    services.AddMvc();  
    services.Configure<MvcOptions>(options =>
    
        options.Filters.Add(new CorsAuthorizationFilterFactory("AllowSpecificOrigin"));
    );


public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)

    app.UseCors("AllowSpecificOrigin");
    app.UseMvc();    

当我在 Visual Studio 中运行这段代码时,它运行良好。但是,当我在 IIS 上发布我的 WebAPI 项目时,我遇到了麻烦:预检请求返回 Status "Code:204 No Content",而 POST 和 PUT 请求返回 “405 方法不允许”

当应用程序托管在 IIS 上时,AllowAnyMethod() 似乎没有任何效果,因为我们可以看到只允许 GET、HEAD、OPTIONS、TRACE从上图看。

为了测试这个东西并消除对 Angular 和 Web API 的怀疑,我创建了测试脚本并在 Chrome 开发者控制台中运行它:

var xmlHttp = new XMLHttpRequest(); //returns a XMLHttpRequest object
xmlHttp.open('PUT', "http://localhost:27895/api/usergroups/58c624eb54d98519e85c5771", true);
xmlHttp.setRequestHeader('Content-Type', "application/json");  
xmlHttp.send(JSON.stringify("id":"58c624eb54d98519e85c5771","Name":"Группа первооткрывателей"));

我从我的 Angular 客户端页面运行此脚本时遇到了同样的问题。比我从托管 WebApi 的同一来源运行此脚本(以检查没有 COR 的 webAPI)。我有一个错误,告诉我现场不允许使用 PUT 方法!

最后,我找到了解决方案:问题出在 IIS 上的 WebDAV 模块,与我的 RESTful 服务冲突。 我在 IIS 上从我的 webAPI 站点中删除了 WEBDAV 模块,现在它可以完美运行了:

为此:

    在 IIS 上选择您的 WebAPI 站点 打开“模块” 查找并删除 WebDAV 选项

也为您的 webApi 站点从 IIS 上的处理程序映射中删除 WebDAV 选项。

如果您想了解更多关于 WEBDAV 和 Web API 冲突的说明,这些主题会很有用:

forum iis.net, forum asp.net


事实证明,WebDav 处理程序和模块在下一次发布后再次出现在 IIS 中。因此,为了防止站点这样做,请修改您的 WebAPI 应用程序的 web.config,如下所示:

<handlers>
   <remove name="WebDAV" />
</handlers>
<modules>
   <remove name="WebDAVModule" />
</modules>

this topic 帮我弄明白了。

【讨论】:

我已经编辑了答案:添加了有关 web.config 首选项的信息 6 小时后,我来到了这里。你的回答拯救了我的学业。谢谢

以上是关于如何让 CORS 与 ASP.Net Core Web API 服务器 Angular 2 客户端一起工作的主要内容,如果未能解决你的问题,请参考以下文章