这是今天遇到的一个实际问题,在这篇随笔中记录一下解决方法。
ASP.NET Web API提供了CORS支持,但ASP.NET MVC默认不支持,需要自己动手实现。可以写一个用于实现CORS的ActionFilterAttribute,我们就是这么实现的:
public class AllowCorsAttribute : ActionFilterAttribute
{
private string[] _domains; public AllowCorsAttribute(string domain)
{
_domains = new string[] { domain };
} public AllowCorsAttribute(string[] domains)
{
_domains = domains;
} public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var context = filterContext.RequestContext.HttpContext;
var host = context.Request.UrlReferrer?.Host;
if (host != null && _domains.Contains(host))
{
context.Response.AddHeader("Access-Control-Allow-Origin", $"http://{host}");
context.Response.AddHeader("Access-Control-Allow-Credentials", "true");
}
base.OnActionExecuting(filterContext);
}
在需要支持CORS的Controller Action上加上[AllowCors("www.cnblogs.com")]标记。
jquery ajax的请求代码如下:
$.ajax({
url: '...',
type: 'get',
xhrFields: {
withCredentials: true
},
dataType: 'application/json; charset=utf-8',
success: function (data) {
//...
}
});
【遇到的问题】
1)一开始在ajax代码中没加"withCredentials: true",发现ajax请求中没带上cookies。
2)加了"withCredentials: true"后,服务端响应出错:
XMLHttpRequest cannot load '{url}'. Credentials flag is 'true', but the 'Access-Control-Allow-Credentials' header is ''. It must be 'true' to allow credentials. Origin 'http://www.cnblogs.com' is therefore not allowed access.
后来在服务端添加了如下的响应头解决了问题:
context.Response.AddHeader("Access-Control-Allow-Credentials", "true");
3)如果是http post,ajax的请求参数中contentType不能用applicaion/json,要用application/x-www-form-urlencoded。
$.ajax({
url: 'cross domain url',
data: { reason: txtReason },
contentType: 'application/x-www-form-urlencoded; charset=utf-8',
type: 'post',
dataType: 'json',
xhrFields: {
withCredentials: true
},
success: function (data) {
//...
}
});