缘起

以前在asp.net mvc时代,很少出现跨域问题

自从使用了asp.net web api + angular (1/2)之后,开始有跨域问题了。

简单普及下跨域:

我的理解是只要是前台页面与后台服务不在同一域名下,或者同域名不同端口下,就是跨域,我做个真值表:

前端 后端 是否跨域
http://localhost:3000 http://localhost:3000  
http://localhost:3000 http://localhost:2000
http://localhost:3000 http://localhost:5000

如果跨域,最直接的表现就如下图:

下面我帖上测试代码(未解决跨域问题之前):

前端:

<script type="text/javascript" src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script type="text/javascript">
$(function () { $("#btn2").click(function () {
$.ajax({
type: "POST",
url: "http://localhost:4272/api/Resources/GetPrintMethod",
success: function (data) {
console.log(data);
},
error: function (e, XMLHttpRequest, textStatus) {
console.log(e);
},
});
});
}); $(function () {
//.ajaxError事件定位到document对象,文档内所有元素发生ajax请求异常,都将冒泡到document对象的ajaxError事件执行处理,ajax方法中有error,先处理error,再冒泡到此处的error
$(document).ajaxError( //所有ajax请求异常的统一处理函数,处理
function (event, xhr, options, exc) {
alert("StatusCode:" + xhr.status);
if (xhr.status == 'undefined') {
return;
}
switch (xhr.status) {
case 403:
// 未授权异常
alert("系统拒绝:您没有访问权限。");
break; case 404:
alert("您访问的资源不存在。");
break;
}
}
);
});
</script> <body>
<input type="button" value="测试跨域请求" id="btn2">
</body>

后端就是一个asp.net web api程序,我就不全贴了,只挑重点了:

目前只有一个Controller:

using System.Collections.Generic;
using System.Threading.Tasks;
using System.Web.Http; namespace Summer.Api.Controllers
{
[RoutePrefix("api/Resources")]
public class ResourcesController : ApiController
{ [Route("GetPrintMethod")]
[HttpPost]
[HttpGet]
public async Task<IHttpActionResult> GetPrintMethod()
{
var list = new List<string>
{
"数据1",
"数据2"
}; return Ok(new { frontPrintMethod = list });
}
}
}

这时,我们运行起来后端,在Controller上打上断点:

然后前端请求:

首先,Controller断点生效,似乎正常通过,return Ok(.....),

But,前台却得到:

这是前端的一个异常捕获,status code是0,0是什么?这显然不是我们想要的

在 https://blog.csdn.net/zheng963/article/details/42237709 我查到了一些端倪:

竟然还没有调用Send方法?这是什么鬼?WTF...为什么会这样呢?

再观察下NetWork看看:

发现有1次请求,并且状态是200,照理说应当没问题了,可为什么会得到statuscode 0呢?

Console还有一行错误信息:

Failed to load http://localhost:4272/api/Resources/GetPrintMethod: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

先看一下详细信息再说:

200,OK,竟然还得到了数据,不错,不错,可是为什么有那行错误信息呢?

那行错误信息

Failed to load http://localhost:4272/api/Resources/GetPrintMethod: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.

这段是说被请求的资源没有允许跨域,所以不允许访问,可是奇怪,不允许访问,为什么还能得到结果呢。。。奇怪。。。不知道是不是Bug。。。。。

尝试解决

下面我来尝试解决它

既然是跨域,那就找解决方案呗,后台是WebApi,NuGet查找并安装 Microsoft.AspNet.WebApi.Cors

然后在WebApiConfig中加上一句:

config.EnableCors(new System.Web.Http.Cors.EnableCorsAttribute("*", "*", "*"));

再次运行请求看下,这次我们成功得到了结果,并没有报错对比下加没加跨域插件下的响应报文头:

我发现加了跨域插件后,响应报文头,自动加了一行:

Access-Control-Allow-Origin: *
有了它,就允许跨域了,问题似乎得到了解决。
 
 

弦外

人就是不满足,现在,我要加需求,我Api现在有了一个要求:

现在我允许了跨域,你爱是哪来哪来,我都允许,但是。。。

(据说但是之前的都是XXX)

你必须要有合法的Token,Token是什么,如何获取,如何验证它是否合法,这里不介绍。

只是我要有一个Token,随便是什么,然后,API来模拟在Action执行前拦截进行Token校验。

先写一个 MyAuthHandler继承自 DelegatingHandler,具体代码如下:

 using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web; namespace Summer.Api.Providers
{
public class MyAuthHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
var authHeader = request.Headers.Authorization; try
{
var token = authHeader.Scheme;
if (string.IsNullOrWhiteSpace(token))
return request.CreateErrorResponse(HttpStatusCode.Forbidden, "invalid_grant. Token is empty.");
} catch (Exception ex)
{
return request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message, ex);
} return await base.SendAsync(request, cancellationToken);
}
}

然后把它加也加在WebApiConfig中:

在MyAuthHandler中我重写了SendAsync方法,这样每当服务器在执行真正Action之前都会先走这个方法,我就可以在这里进行请求合法性检测了。

运行前端再次请求,依然得到了StatusCode 0,和500错误,并且,跨域的问题又回来了:

好难缠啊,又跨域,似乎那插件没有对新加的Handler起作用。

分析下:

500,是因为请求Headers中没有Authorization,更加没有Token,所以我们直接返回

return request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message, ex);

这个OK

但为什么我没有得到这500,而却得到了0?

观察下响应头:

呃,问题原来在这里,响应头中又没有了:

Access-Control-Allow-Origin: *

好吧,插件不起作用,我手动加上总可以了吧

Handler中改一下:

再次调用查看结果:

Excellent, That's what I really needed.

终于得到了我想要的正确的Code问题完美解决。

尾声

回顾下过程:

1.出现跨域

2.引用Cros插件解决跨域

3.新增需求,要在Action执行前进行Token验证

4.新增MyAuthHandler : DelegatingHandler来在每一次执行Action前进行拦截检测

5.拦截后又出现跨域,Cros插件未对其起作用

6.手动为Response添加允许跨域响应头:

Access-Control-Allow-Origin: *

7.问题遭到解决

But:

为什么在没有加允许跨域时,虽然得到错误,却也得到了数据呢?

Angular

再次使用Angular2来调用WebApi

依然可以得到正确Code,跨域问题完美解决在 Asp.net Web Api

.net Core中似乎不存在这么复杂,没有继续测试

node里,其实更加简单,只要在每次返回时加上允许跨域头即可。

asp.net web api 跨域问题的更多相关文章

  1. ASP.NET web api 跨域请求

    1.学习文章:AJAX 跨域请求 - JSONP获取JSON数据 1.asp.net代码 参考文章:http://www.sxt.cn/info-2790-u-756.html (1).增加CorsH ...

  2. ASP.NET Web API 跨域访问(CORS)

    一.客户端用JSONP请求数据 如果你想用JSONP来获得跨域的数据,WebAPI本身是不支持javascript的callback的,它返回的JSON是这样的: {"YourSignatu ...

  3. asp.net web api 跨域,带cookie

    官网上有一个介绍 http://www.asp.net/web-api/overview/security/enabling-cross-origin-requests-in-web-api 但是只支 ...

  4. ASP.NET Web API 跨域访问(CORS)要注意的地方

    一.客户端用JSONP请求数据 如果你想用JSONP来获得跨域的数据,WebAPI本身是不支持javascript的callback的,它返回的JSON是这样的: {"YourSignatu ...

  5. ASP.NET Web API 跨域访问

    自定义特性 要在WebApi中实现JSONP,一种方式是实现自定义特性  http://stackoverflow.com/questions/9421312/jsonp-with-asp-net-w ...

  6. Web Api跨域访问配置及调用示例

    1.Web Api跨域访问配置. 在Web.config中的system.webServer内添加以下代码: <httpProtocol> <customHeaders> &l ...

  7. ASP.NET Core Web API 跨域(CORS) Cookie问题

    身为一个Web API,处理来自跨域不同源的请求,是一件十分合理的事情. 先上已有的文章,快速复制粘贴,启用CORS: Microsoft:启用 ASP.NET Core 中的跨域请求 (CORS) ...

  8. ABP框架Web API跨域问题的解决方案

    ​1.在Web Api 项目下安装 Microsoft.AspNet.WebApi.Cors 包 Install-Package Microsoft.AspNet.WebApi.Cors 2.在Web ...

  9. web api 跨域请求,ajax跨域调用webapi

    1.跨域问题仅仅发生在Javascript发起AJAX调用,或者Silverlight发起服务调用时,其根本原因是因为浏览器对于这两种请求,所给予的权限是较低的,通常只允许调用本域中的资源,除非目标服 ...

随机推荐

  1. android源码下载/查看地址

    源码下载: http://git.omapzoom.org/ 高通平台android源码下载地址: https://www.codeaurora.org/xwiki/bin/QAEP/WebHome ...

  2. hbase shell 命令

    HBase使用教程 时间 2014-06-01 20:02:18 IT社区推荐资讯 原文  http://itindex.net/detail/49825-hbase 主题 HBase 1     基 ...

  3. SQL Server 2008中的MERGE(不仅仅是合并)

    SQL Server 2008中的MERGE语句能做很多事情,它的功能是根据源表对目标表执行插入.更新或删除操作.最典型的应用就是进行两个表的同步. 下面通过一个简单示例来演示MERGE语句的使用方法 ...

  4. Alpha 冲刺 (2/10)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 协助前端界面的开发 搭建测试用服务器的环境 完成 ...

  5. 类似 QQ 音乐底部常驻播放栏(AVQueuePlayer)

    一开始搞了个基类,但是这样所有类都要继承它才可以.后来考虑把他加到 window 上.但是在 appdelegate 中没有办法可以加到上面,最后在 keyWindow 的rootViewContro ...

  6. java web各个技术细节总结

    HTML 非表单标签 1.b 粗体   u 下划线 i 斜体 del 删除效果 2.a  超链接  href  target=-blank 3.img 图片 4.frameset(frame)  框架 ...

  7. shell 报错 /bin/bash^M: bad interpreter: No such file or directory

    shell 执行报错: ./test.sh: /bin/bash^M: bad interpreter: No such file or directory 原因:window和linux 的文件格式 ...

  8. java 模拟登录新浪微博(通过cookie)

    这几天一直在研究新浪微博的爬虫,发现爬取微博的数据首先要登录.本来打算是通过账号和密码模拟浏览器登录.但是现在微博的登录机制比较复杂.通过账号密码还没有登录成功QAQ.所以就先记录下,通过cookie ...

  9. 2018.11.01 NOIP训练 梭哈(模拟)

    传送门 这题貌似不考智商啊. 直接按题意写就可以了. 事实上把牌从小到大排序之后写起来很舒服的. 然后就是有些地方可以人脑减代码量和判断次数. (提示:满堂红和某几种同类型的牌的大小判断) 然后注意A ...

  10. Le Chapitre X

    Il se trouvait dans la région des astéroïdes 325, 326, 327, 328, 329 et 330. Il commença donc par le ...