WCF SOA --- AJAX 跨域请求处理 CORS for WCF
一、问题
跨域请求无法处理的问题,由于为了阻止恶意的网站通过JS脚本来窃取正常网站受保护的资源。所由所有的浏览器的默认策略是阻止XmlHttpRequest的跨域的异步请求。 但是对于一个 复合型的应用集合来说,可能需要使用不同的域来部署我们的应用。对于这种正常的需求,我们的服务与应用就需要能够支持指定信认域的跨域的异步请法。
通常来说,我们有三种替代方案
1, 使用JSONP,
JSONP(JSON with Padding), 但由于JSONP使用的是在HTML DOM中加入<script>标签来包裹来对提供GET的服务请求数据,所有JSONP只对HTTP GET方式的请求取作用。我们的SOA框架,大多是使用POST的请求。
2, 使用分离的“Proxy”代理服务,
代理服务是指,在同一个请求的域下创建一个代理的服务, Ajax请求这个代理服务,由代理服务来路由这个请求到目标域的服务上。 如果我们的所有的运用都必须使用HTML页面来实现。 那这种方式,需要为每一个不同域的应用创建代理服务。 但请注意,如果我们的应用是门户网,请求可能来自外面的人, 对于性能需求高,那么使用HTML是不可行的。我们需要使用ASP.NET MVC结构, 那么Controller层就如同我们的代理服务层。
3, 使用CORS
CORS,Cross-Origin Resource Sharing, 这是一种新的对跨域支持的方法, 它是通过定义一系列的HTTP Headers 在Service 与Client, 服务端可以去掉对于跨域的约束,不仅可以使用GET,还可以使用POST, PUT,或是DELETE, XmlHttpRequest对象已经实现了CORS, 将它作为正常的AJAX调用。但是目前只有最新版本的浏览器才支持, 对于Firefox 3.5以下,Safari 4以下,Chrome 3以下, IE 10 以下,可以使用XDomainRequest对象来代替XmlHttpRequest对象来实现。
浏览器对于使用CORS的请求,会分成次请求,第一次,预先授权请求,会将请求的方式变成OPTIONS, 请求的数据为空,这个过程实际上是在看当前的Origin是否被服务允许,如果允许只服务返回200OK, 否则返回405 Method NOT Allowed, 第二次,正常请求,浏览器将请求的数据POST发送服务,服务端会正常响应。 注意下面是Chrome的,IE的话,只会显示一条。

二、解决步骤。
1, 应用, 对于应用层来说, 该怎么样写,还是怎么样写,不需要变化。但对于底版本的浏览器的支持需要改代码,不能使用XmlHttpRequest。需要使用XDomainRequest。
2, 服务, 这里我们使用的是WCF, 对于使用ASP.NET Web API的话,使用参考:https://msdn.microsoft.com/en-us/magazine/dn532203.aspx, 或是Google, CORS in ASP.NET Web Api.
对于WCF,我参考了 CarlosFigueira写的 http://blogs.msdn.com/b/carlosfigueira/archive/2012/05/15/implementing-cors-support-in-wcf.aspx ,文章写的非常不错, 但是我发现,其它它是一个半成品,没有实现玩,它的目的是创建一个新的Operation,只是支持OPTIONS方式的请求,Action的名称是当前操作的名称 +特定的后缀。 但这样问题来了,客户端浏览器的请求,每一次不会自动加上这个后缀,所有Invoke一直都不会被调用。 大家的兴趣下载了使用的话,如果想结合到自己的项目中, 可要记得把Web.config中的<modules runAllManagedModulesForAllRequests="true">去掉。 当然,前提是,你使用的Service都是自己通过ServiceHostFactory创建出来的, 如果使用默认的,是不会支持的。 其它 CarlosFigueira想法。 我做了一些改变。 实现步骤如下:
1,在IIS中,添加Http Response Header 3个,如下

建议这个设置在WebSite上, 这样你的服务在这个Website下作为一个Web Application的话,将自动继承这些配置。 写在web.config,可以方便控制允许访问的域。当前我使用 *, 这样所有的域都能访问,如果想指定哪些域的话,可以改成如 Http://domain1.com,Http://domain2......。那么只有来自这些域的请求才能处理。当然这个设置,或以在WCF,添加自己的IDispatchMessageInspector实现, 在BeforeSendReply事件中,添加响应头。
2,在使用自定ServiceHostFactory,创建服务时, 我们可以指定IServiceBehavior, 在它的ApplyDispatchBehavior事件中。 找到所有的Operation,对它注入WebInvokeAttribute, Method设置成*, 目的是动态将Operation对 Method=OPTIONS的请求处理, 如下代码
foreach (ServiceEndpoint endpoint in desc.Endpoints)
{
foreach (var operation in endpoint.Contract.Operations)
{
//Add WebInvoke Attribute to all operation except for WebGet only, so that our opeations are able to handle OPTIONS Http Request Method for CORS issue.
if ( !operation.Behaviors.Any(d => d is WebGetAttribute)
&& !operation.Behaviors.Any(d => d is WebInvokeAttribute))
{
WebInvokeAttribute wia = new WebInvokeAttribute();
wia.UriTemplate = operation.Name;
wia.Method = "*";
operation.Behaviors.Add(wia);
}
}
}
3,当OPTIONS方式的请求来到时,在自定的 IOperationInvoker的invoke事件中, 判断当前的Http Method是否为OPTIONS, 如果是的话,不处理正常逻辑, 返回一个200 OK的响应。代码如下
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
string operationName = "";
if (OperationContext.Current.IncomingMessageHeaders.Action != null)
{
operationName = OperationContext.Current.IncomingMessageHeaders.Action.ToString();
}
if (OperationContext.Current.IncomingMessageProperties.Keys.Contains("HttpOperationName"))
{
operationName = OperationContext.Current.IncomingMessageProperties["HttpOperationName"].ToString();
}
HttpRequestMessageProperty request = System.ServiceModel.OperationContext.Current.IncomingMessageProperties["httpRequest"] as HttpRequestMessageProperty;
//If enable CORS, then we need to handle OPTIONS Method to reply OK, so that the browser will seed the right POST request.
if (request != null
&& request.Method == "OPTIONS" )
{
System.ServiceModel.Channels.Message input = (System.ServiceModel.Channels.Message)inputs[0];
outputs = null;
return HandlePreflight(input, operationName);
}
else
{
正常处理。。。。
}
}
System.ServiceModel.Channels.Message HandlePreflight(System.ServiceModel.Channels.Message input, string operationName)
{
System.ServiceModel.Channels.Message reply = System.ServiceModel.Channels.Message.CreateMessage(MessageVersion.None, operationName);
HttpResponseMessageProperty httpResponse = new HttpResponseMessageProperty();
reply.Properties.Add(HttpResponseMessageProperty.Name, httpResponse);
httpResponse.SuppressEntityBody = true;
httpResponse.StatusCode = System.Net.HttpStatusCode.OK;
httpResponse.Headers.Add(CorsConstants.AccessControlAllowOrigin, "*");
httpResponse.Headers.Add(CorsConstants.AccessControlAllowMethods, string.Join(",", new List<string>() { "POST", "GET", "OPTIONS" }));
return reply;
}
结束。
WCF SOA --- AJAX 跨域请求处理 CORS for WCF的更多相关文章
- JQuery.Ajax + 跨域 (crossDomain) + POST + JSON + WCF RESTful, 5大陷阱和解决方案
JQuery.Ajax + 跨域 (crossDomain) + POST + JSON + WCF RESTful, 5大陷阱和解决方案 最近在开发WSS RESTful服务的时候, 碰到了这些个纠 ...
- Springmvc ajax跨域请求处理
上次给一个网站写网站 前后端分离 最后跪在ajax跨域上面了 自己在网上找了个方法 亲试可用 记录一下 写一个类 继承HandlerInterceptorAdapter package co ...
- [经验] - JQuery.Ajax + 跨域 (crossDomain) + POST + JSON + WCF RESTful, 5大陷阱和解决方案
最近在开发WSS RESTful服务的时候, 碰到了这些个纠结的问题. 在网上查找了半天, 找到n多种解决方案, 但是都是部分的, 要么是没有跨域的情况, 要么是没有post的情况, 要么不是用WCF ...
- AJAX跨域资源共享 CORS 详解
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing). 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从 ...
- Jquery:ajax跨域请求处理
昨天朋友想做个图片懒加载的效果,朋友是前端的,我这边给他提供数据,程序写好了放到服务器上,本地测试访问时却报jquery跨域的问题,于是找度娘了解了一下jquey如何处理,网上有很多参考文章,但没细看 ...
- Ajax 跨域 异步 CORS
HTTP access control (CORS) 核心在于使用定制(添加新的header)HTTP header让浏览器和服务器有更多的相互了解,从而决定一个请求或者响应成功还是失败 对于一个 ...
- ajax跨域通过 Cors跨域资源共享 进行GetPost请求
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Ne ...
- ajax 跨域了 cors
<?php /** * Author: humanhuang * Date: 13-12-17 */ header('Access-Control-Allow-Origin:*'); heade ...
- 分享知识-快乐自己:Ajax 跨域请求处理
<%-- Created by IntelliJ IDEA. User: asus Date: 2019/1/24 Time: 15:57 To change this template use ...
随机推荐
- js学习之函数声明与函数表达式区别[原创]
作为一名js初学者,与大家分享下.Javascript中有函数声明提升的功能,会优先编译函数声明部分.比如, ff(); function ff(){ alert("hello world. ...
- 你不需要jQuery(五)
什么不用jQuery?因为它让你的网站体积变得臃肿.你的网站并不真的需要jQuery,不需要它带来的额外体积.带宽和加载时间. 用原生JavaScript简单实现jQuery提供的功能和方法 查找.选 ...
- 团体程序设计天梯赛-练习集L2-002. 链表去重
L2-002. 链表去重 时间限制 300 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 给定一个带整数键值的单链表L,本题要求你编写程序,删除 ...
- 【图说】Eclipse与Unity 3D协同工作
原地址:http://blog.csdn.net/h570768995/article/details/9355313 Eclipse开发过程中总会碰到很多的难题,如何利用好工具帮助我们更快捷的开发也 ...
- python datetime笔记
python datetime笔记 http://mint-green.diandian.com/post/2011-09-09/4892024 获取当前时间,并通过字符串输出. 格式为:%Y-%m- ...
- linux useradd添加用户
useradd命令用来建立用户帐号和创建用户的起始目录,使用权限是超级用户. useradd -m -s /bin/bash -g 群组名 用户名 其中 -m:自动建立用户的登入目录. -s:指定用户 ...
- HeadFirst设计模式之代理模式
一. 1.The Proxy Pattern provides a surrogate or placeholder for another object to control access to i ...
- ArcGIS学习记录—KMZ KML与SHP文件互相转换
1.在google earth中绘制边界 工具栏中选择"Add Polygon".随意绘制一个多边形. 右击添加的图层名(左侧)保存位置为,选择保存为kmz或kml文件. ...
- WPF之监听组合键事件
private void KeyDown(object sender, KeyEventArgs e) { if (e.Key== Key.Up && Keyboard.Modifie ...
- centos更新163源并升级内核
使用说明 首先备份/etc/yum.repos.d/CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/Cen ...