As.net WebAPI CORS, 开启跨源访问,解决错误No 'Access-Control-Allow-Origin' header is present on the requested resource

默认情况下ajax请求是有同源策略,限制了不同域请求的响应。

例子:http://localhost:23160/HtmlPage.html 请求不同源API http://localhost:22852/api/values,

What is "Same Origin"?

Two URLs have the same origin if they have identical schemes, hosts, and ports. (RFC 6454)

These two URLs have the same origin:

  • http://example.com/foo.html
  • http://example.com/bar.html

These URLs have different origins than the previous two:

  • http://example.net - Different domain
  • http://example.com:9000/foo.html - Different port
  • https://example.com/foo.html - Different scheme
  • http://www.example.com/foo.html - Different subdomain

http://localhost:23160/HtmlPage.html 代码如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script src="Scripts/jquery-1.10.2.min.js"></script>
<script type="text/javascript">
$(function () {
$("#Button1").click(function () {
$.ajax({
url: "http://localhost:22852/api/values",
success: function (data) {
alert(data);
}
});
});
});
</script>
</head>
<body>
<input id="Button1" type="button" value="button" />
</body>
</html>

通过调试我们发现,ajax请求成功发送到API,API后台的断点走到了,并且返回了数据,并没有什么问题。 在web端,查看网络,显示的status状态也是200,但是响应的内容却是空的。

这时,查看控制台会发现错误:XMLHttpRequest cannot load http://localhost:22852/api/values. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:23160' is therefore not allowed access.

提示API响应头中没有‘Access-Control-Allow-Origin'头,标识可以允许源http://localhost:23160访问。

我们发现,同源策略,并没有阻止请求的发送,但是阻止了,不同源请求的响应。

如何对指定的源,开放访问?

微软的工程师已经给出了解决方案,直接在安装一个现成的package就能解决。

1.add the CORS NuGet package. In Visual Studio, from the Tools menu, select Library Package Manager, then select Package Manager Console. In the Package Manager Console window, type the following command:

Install-Package Microsoft.AspNet.WebApi.Cors  

This command installs the latest package and updates all dependencies, including the core Web API libraries. User the -Version flag to target a specific version. The CORS package requires Web API 2.0 or later.

2.Open the file App_Start/WebApiConfig.cs. Add the following code to the WebApiConfig.Register method.

using System.Web.Http;
namespace WebService
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// enable cors
config.EnableCors(); config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}

3. Next, add the [EnableCors] attribute to the TestController class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
using System.Web.Http.Cors; namespace ServerSide.Controllers
{
[EnableCors(origins: "http://localhost:23160", headers: "*", methods: "*")]
public class TestController : ApiController
{
public HttpResponseMessage Get()
{
return new HttpResponseMessage()
{
Content = new StringContent("GET: Test message")
};
}
}
}

经过以上3个步骤,在web端调用API后,成功获取响应内容:”GET: Test message“

详细请参考:http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters

我走的弯路:

1.可能是VS2013的原因,安装了Microsoft.AspNet.WebApi.Cors包之后,生成成功,运行的时候,报错:未能加载文件或程序集“System.Web.Http”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。我一看,是因为引用的版本不一致,但是packages中和Bin中都是存放的最新的5.2.3版本的,只是却报错说找不到5.0.0版本,很奇怪,5.0.0版本是安装Cors包之前版本,安装cors包会把依赖的system.web.http自动升级到5.2.3,把l5.0.0的老版本删掉了。为什么还是报这个错误。而且很奇怪的是,web.config中并没有dll引用的配置,package.config中也没有,以前.net项目,dll的版本维护都是在web.config中,难道WebAPI换了方式,那是怎么配置的呢,网上也没有找到答案,后来我查看我本地其它API项目,发现dll是在web.config中配置的呀。 于是尝试按照其它项目一样,在webconfig中configuration根目录添加runtime阶段配置assemblyBinding,指定5.2.3版本的dll,成功解决问题,web.config代码如下:

<?xml version="1.0" encoding="utf-8"?>
<!--
For more information on how to configure your ASP.NET application, please visit
http://go.microsoft.com/fwlink/?LinkId=301879
-->
<configuration>
<appSettings>
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
</system.web> <system.webServer>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<remove name="OPTIONSVerbHandler" />
<remove name="TRACEVerbHandler" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
</dependentAssembly>
</assemblyBinding>
</runtime> </configuration>

2.上面的问题解决后,忘记了在App_Start/WebApiConfig.cs中添加配置,仅仅在Controller类上添加了attribute,还是不能跨源访问,以为是我VS哪里出问题了,我的版本是VS2013,作者是VS2013 Update2,又尝试去升级。最后重新走一遍流程,才发现遗漏配置了,添加配置后,终于能够跨源请求,正确获取响应了。

上一篇:JAVA线程池的分析和使用


下一篇:STM32学习笔记(九) 外部中断,待机模式和事件唤醒