缘起

以前在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. ssrf绕过总结

    前言 昨天忘了在公众号还是微博上看到的了,看到一个SSRF绕过的技巧,使用的是 ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ 绕过的,自己也没遇到过.然后想想自己对SSRF绕过还是停留在之前的了解,也没学习过新的绕过方法, ...

  2. Java:斐波那契数列

    斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10 ...

  3. 别人的Linux私房菜(2)Linux简介

    同一操作系统无法在不同硬件平台上运行.架构. Bell实验室和麻省理工学院MIT和通用电气公司GE发起了Multics计划,分时兼容系统,300以上多终端连接主机. Unics 由Multics中的人 ...

  4. RBAC简介

    1.RBAC 中文名称:基于角色的访问控制 1.1 作用:实现访问控制 1.2 核心:角色 2.英文名称:(Role-Based Access Control) 3.解释:一种思想,根据RBAC思想进 ...

  5. GDI基础(1):绘制线条和图形

    1. 绘制一个像素点:SetPixel(). 绘制直线:MoveTo(),LineTo(). 绘制多个首尾相连的线:Polyline(). 绘制矩形:FrameRect(),Rectangle(),F ...

  6. IntelliJ IDEA 2017版 Spring5最基本的bean例子创建

    一.简述         SpringBoot是基于spring框架之上的快速开发的框架.Spring4核心就是容器,容器提供了对bean的装配和管理.       spring依赖加载:       ...

  7. mysql学习之路_基础知识

                    Mysql php阶段将数据库分为三个阶 基础阶段: mysql数据库的基本操作(增删改查),以及一些高级操作(视图,触发器,函数,存储过程等),PHP操作没有sql数 ...

  8. UVa 11722 Joining with Friend (几何概率 + 分类讨论)

    题意:某两个人 A,B 要在一个地点见面,然后 A 到地点的时间区间是 [t1, t2],B 到地点的时间区间是 [s1, s2],他们出现的在这两个区间的每个时刻概率是相同的,并且他们约定一个到了地 ...

  9. javascript 连等赋值问题

    var a = {n:1}; var b = a; // 持有a,以回查 a.x = a = {n:2}; alert(a.x);// --> undefined alert(b.x);// - ...

  10. ubuntu16.04 编译安卓4.2

    1. root@ge-Lenovo:/usr/lib/jvm# cd /home/material/install/jdk/    jdk-6u29-linux-x64.bin  jdk-6u45-l ...