概述

ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作。但是在使用API的时候总会遇到跨域请求的问题,

特别各种APP万花齐放的今天,API的跨域请求是不能避免的。

在默认情况下,为了防止CSRF跨站的伪造攻击(或者是 javascript的同源策略(Same-Origin Policy)),一个网页从另外一个域获取数据时就会收到限制。有一些方法可以突破这个限制,那就是大家熟知的JSONP, 当然这只是众多解决方法中一种,由于JSONP只支持GET的请求,如今的复杂业务中已经不能满足需求。而CORS(Cross Origin Resource Sharing https://www.w3.org/wiki/CORS)跨域资源共享,是一种新的header规范,可以让服务器端放松跨域的限制,可以根据header来切换限制或者不限制跨域请求。重要的是它支持所有http请求方式。

问题

XMLHttpRequest 跨域 POST或GET请求 ,请求方式会自动变成OPTIONS的问题。

由于CORS(cross origin resource share)规范的存在,浏览器会首先发送一次options嗅探,同时header带上origin,判断是否有跨域请求权限,服务器响应access control allow origin的值,供浏览器与origin匹配,如果匹配则正式发送post请求,即便是服务器允许程序跨域访问,若不支持 options 请求,请求也会死掉。

原因

浏览器为了安全起见,会Preflighted Request的透明服务器验证机制支持开发人员使用自定义的头部、GET或POST之外的方法,以及不同类型的主题内容,也就是会先发送一个 options 请求,

问问服务器是否会正确(允许)请求,确保请求发送是安全的。

出现 OPTIONS 的情况一般为:

1、非GET 、POST请求

2、POST请求的content-type不是常规的三个:application/x- www-form-urlencoded(使用 HTTP 的 POST 方法提交的表单)、multipart/form-data(同上,但主要用于表单提交时伴随文件上传的场合)、text/plain(纯文本) 

3、POST请求的payload为text/html 

4、设置自定义头部

OPTIONS请求头部中会包含以下头部:Origin、Access-Control-Request-Method、Access-Control-Request-Headers,发送这个请求后,服务器可以设置如下头部与浏览器沟通来判断是否允许这个请求。

Access-Control-Allow-Origin、Access-Control-Allow-Method、Access-Control-Allow-Headers

解决方法

此方法功能强大,可以解决ASP.NET Web API复杂跨域请求,携带复杂头部信息,正文内容和授权验证信息

方法一

  1. public class CrosHandler:DelegatingHandler
  2. {
  3. private const string Origin = "Origin";
  4. private const string AccessControlRequestMethod = "Access-Control-Request-Method";
  5. private const string AccessControlRequestHeaders = "Access-Control-Request-Headers";
  6. private const string AccessControlAllowOrign = "Access-Control-Allow-Origin";
  7. private const string AccessControlAllowMethods = "Access-Control-Allow-Methods";
  8. private const string AccessControlAllowHeaders = "Access-Control-Allow-Headers";
  9. private const string AccessControlAllowCredentials = "Access-Control-Allow-Credentials";
  10. protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
  11. {
  12. bool isCrosRequest = request.Headers.Contains(Origin);
  13. bool isPrefilightRequest = request.Method == HttpMethod.Options;
  14. if (isCrosRequest)
  15. {
  16. Task<HttpResponseMessage> taskResult = null;
  17. if (isPrefilightRequest)
  18. {
  19. taskResult = Task.Factory.StartNew<HttpResponseMessage>(() =>
  20. {
  21. HttpResponseMessage response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
  22. response.Headers.Add(AccessControlAllowOrign,
  23. request.Headers.GetValues(Origin).FirstOrDefault());
  24. string method = request.Headers.GetValues(AccessControlRequestMethod).FirstOrDefault();
  25. if (method != null)
  26. {
  27. response.Headers.Add(AccessControlAllowMethods, method);
  28. }
  29. string headers = string.Join(", ", request.Headers.GetValues(AccessControlRequestHeaders));
  30. if (!string.IsNullOrWhiteSpace(headers))
  31. {
  32. response.Headers.Add(AccessControlAllowHeaders, headers);
  33. }
  34. response.Headers.Add(AccessControlAllowCredentials, "true");
  35. return response;
  36. }, cancellationToken);
  37. }
  38. else
  39. {
  40. taskResult = base.SendAsync(request, cancellationToken).ContinueWith<HttpResponseMessage>(t =>
  41. {
  42. var response = t.Result;
  43. response.Headers.Add(AccessControlAllowOrign,
  44. request.Headers.GetValues(Origin).FirstOrDefault());
  45. response.Headers.Add(AccessControlAllowCredentials, "true");
  46. return response;
  47. });
  48. }
  49. return taskResult;
  50. }
  51. return base.SendAsync(request, cancellationToken);
  52. }
  53. }

使用方式,在Global.asax文件添加

  1. protected void Application_Start()
  2. {
  3. IOCConfig.RegisterAll();
  4. AreaRegistration.RegisterAllAreas();
  5. WebApiConfig.Register(GlobalConfiguration.Configuration);
  6. FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
  7. RouteConfig.RegisterRoutes(RouteTable.Routes);
  8. BundleConfig.RegisterBundles(BundleTable.Bundles);
  9. GlobalConfiguration.Configuration.MessageHandlers.Add(new CrosHandler());
  10. }

方法二

配置文件中添加如下配置,此方法简单,应对简单的跨域请求

  1. <system.webServer>
  2. <httpProtocol>
  3. <customHeaders>
  4. <add name="Access-Control-Allow-Origin" value="*" />
  5. <add name="Access-Control-Allow-Headers" value="Content-Type" />
  6. <add name="Access-Control-Allow-Methods" value="GET, POST,OPTIONS" />
  7. </customHeaders>
  8. </httpProtocol>
  9. <system.webServer>

参考文献

https://code.msdn.microsoft.com/windowsdesktop/Implementing-CORS-support-a677ab5d#content

WebApi Ajax 跨域请求解决方法(CORS实现)的更多相关文章

  1. WebApi Ajax 跨域请求解决方法(CORS实现)(作者:jianxuanbing)

    概述 ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.但是在使用API的时候总会遇到跨域请求的问题,特别各 ...

  2. 第114天:Ajax跨域请求解决方法(二)

    一.什么是跨域 我们先回顾一下域名地址的组成: http:// www . google : 8080 / script/jquery.js   http:// (协议号)       www  (子 ...

  3. 第113天:Ajax跨域请求解决方法

    一.原生JS实现ajax 第一步获得XMLHttpRequest对象 第二步:设置状态监听函数 第三步:open一个连接,true是异步请求 第四部:send一个请求,可以发送一个对象和字符串,不需要 ...

  4. Access to XMLHttpRequest at 'XXX' from origin 'XX' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present o AJAX跨域请求解决方法

    今天出现了一个问题找了好久先看代码: 这可能是个BUG吧插入代码: dataType: 'jsonp', crossDomain: true, 最终:

  5. Nginx反向代理、CORS、JSONP等跨域请求解决方法总结

    由于 Javascript 同源策略的存在使得一个源中加载来自其它源中资源的行为受到了限制.即会出现跨域请求禁止. 通俗一点说就是如果存在协议.域名.端口或者子域名不同服务端,或一者为IP地址,一者为 ...

  6. 客户端ajax请求为实现Token验证添加headers后导致正常请求变为options跨域请求解决方法

    客户端为了实现token认证,通过Jquery的ajaxSetup方法全局配置headers: 全局配置headers后会导致部分不需要token认证的请求变为options请求,导致跨域访问.报错信 ...

  7. 基于.Net Framework 4.0 Web API开发(5):ASP.NET Web APIs AJAX 跨域请求解决办法(CORS实现)

    概述:  ASP.NET Web API 的好用使用过的都知道,没有复杂的配置文件,一个简单的ApiController加上需要的Action就能工作.但是在使用API的时候总会遇到跨域请求的问题,特 ...

  8. express 请求跨域后端解决方法CORS

    CORS全称Cross-Origin Resource Sharing,是HTML5规范定义的如何跨域访问资源. Origin表示本域,也就是浏览器当前页面的域.当JavaScript向外域(如sin ...

  9. Ajax跨域请求action方法,无法传递及接收cookie信息(应用于系统登录认证及退出)解决方案

    最近的项目中涉及到了应用ajax请求后台系统登录,身份认证失败,经过不断的调试终于找到解决方案. 应用场景: 项目测试环境:前端应用HTML,js,jQuery ajax请求,部署在Apache服务器 ...

随机推荐

  1. 用Eclipse的snippets功能实现代码重用

    snippets功能实现代码重用 Snippets 代码片段是Eclipse的一个插件. 很多时候可以通过这个功能,重复使用常用的代码片段,加快开发效率. 创建一个代码段的步骤: 在Eclipse的e ...

  2. 6.javaweb之respose对象

    1.respose的生成的outer对象要优先于内置的out对象输出 response.setContentType("text/html;charaset=utf-8");//设 ...

  3. WCF学习——构建第二个WCF应用程序(五)

    一.创建数据服务 1.在“解决方案资源管理器”中,使用鼠标左键选中“WcfService”项目,然后在菜单栏上,依次选择“项目”.“添加新项”. 2.在“添加新项”对话框中,选择“Web”节点,然后选 ...

  4. python2和python3中的类

    经典类与新式类 例如: A B C D 四个类 D 包含 BC :   B和C分别包含A py2 在经典类中是按深度优先来继承 例如: D中查找B,B没有从A中查找 新式类中是按广度优先来查找继承的 ...

  5. biz-NewsService

    package com.pb.news.service; import java.util.List; import com.pb.news.entity.News; public interface ...

  6. Unity3D-Shader-实现X光效果

    [旧博客转移 - 2016年1月3日 16:40 ] 最近学习了一些Shader效果,打算把学到的知识总结一下,这篇讲一下这种轮廓发光的效果(如下图所示),也有一些地方管这个叫X光     1.原理 ...

  7. 推荐系统那点事 —— 基于Spark MLlib的特征选择

    在机器学习中,一般都会按照下面几个步骤:特征提取.数据预处理.特征选择.模型训练.检验优化.那么特征的选择就很关键了,一般模型最后效果的好坏往往都是跟特征的选择有关系的,因为模型本身的参数并没有太多优 ...

  8. Quartz的Hello world

    1.准备环境jar包 Your project will need (at least) the Quartz core library, named quartz-x.y.z.jar (where ...

  9. 微信小程序的登陆流程详解

    由于小程序的登陆和登陆状态维护流程比较复杂,需要客户端和服务器的数次交互以及服务器端的相应处理,很多同学都觉得比较麻烦,所以特别写下这篇博客为大家梳理一下微信的登陆流程,同时加深对微信小程序与登陆状态 ...

  10. sqlserver提高篇

    Microsoft SQL Server2008复习提高 一.Microsoft SQL Server 系统的体系结构 1.Microsoft SQL Server2008由4个主要的部分组成,即4个 ...