一、问题

       跨域请求无法处理的问题,由于为了阻止恶意的网站通过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的更多相关文章

  1. JQuery.Ajax + 跨域 (crossDomain) + POST + JSON + WCF RESTful, 5大陷阱和解决方案

    JQuery.Ajax + 跨域 (crossDomain) + POST + JSON + WCF RESTful, 5大陷阱和解决方案 最近在开发WSS RESTful服务的时候, 碰到了这些个纠 ...

  2. Springmvc ajax跨域请求处理

    上次给一个网站写网站  前后端分离 最后跪在ajax跨域上面了  自己在网上找了个方法  亲试可用  记录一下 写一个类  继承HandlerInterceptorAdapter package co ...

  3. [经验] - JQuery.Ajax + 跨域 (crossDomain) + POST + JSON + WCF RESTful, 5大陷阱和解决方案

    最近在开发WSS RESTful服务的时候, 碰到了这些个纠结的问题. 在网上查找了半天, 找到n多种解决方案, 但是都是部分的, 要么是没有跨域的情况, 要么是没有post的情况, 要么不是用WCF ...

  4. AJAX跨域资源共享 CORS 详解

    CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing). 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从 ...

  5. Jquery:ajax跨域请求处理

    昨天朋友想做个图片懒加载的效果,朋友是前端的,我这边给他提供数据,程序写好了放到服务器上,本地测试访问时却报jquery跨域的问题,于是找度娘了解了一下jquey如何处理,网上有很多参考文章,但没细看 ...

  6. Ajax 跨域 异步 CORS

    HTTP access control (CORS) 核心在于使用定制(添加新的header)HTTP header让浏览器和服务器有更多的相互了解,从而决定一个请求或者响应成功还是失败   对于一个 ...

  7. ajax跨域通过 Cors跨域资源共享 进行GetPost请求

    using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Ne ...

  8. ajax 跨域了 cors

    <?php /** * Author: humanhuang * Date: 13-12-17 */ header('Access-Control-Allow-Origin:*'); heade ...

  9. 分享知识-快乐自己:Ajax 跨域请求处理

    <%-- Created by IntelliJ IDEA. User: asus Date: 2019/1/24 Time: 15:57 To change this template use ...

随机推荐

  1. 一个简单的aJax——后台用servlet技术

    示例:webDemo 一.客户端 <%-- Created by IntelliJ IDEA. User: Administrator Date: 15-12-2 Time: 上午5:41 To ...

  2. 团体程序设计天梯赛-练习集L1-016. 查验身份证

    L1-016. 查验身份证 时间限制 400 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 陈越 一个合法的身份证号码由17位地区.日期编号和顺序编号 ...

  3. eclipse代码自动提示功能设置

    一 般默认情况下,Eclipse ,MyEclipse的代码提示功能是比Microsoft Visual Studio的差很多的,主要是Eclipse ,MyEclipse本身有很多选项是默认关闭的, ...

  4. cocos2d-x 扩充引擎基类功能 引起的头文件重复包含问题的分析

    c++ 头文件包含 原因的分析:   c++  头文件的循环引用是指: .h 里面的里面的头文件的相互包含的,引起的重复引用的问题.cpp 里面包含头文件是不存在重复引用的问题(因为CPP没有#ifn ...

  5. Servlet课程0426(八)Servlet分页技术

    Welcome.java //登录界面 package com.tsinghua; import javax.servlet.http.*; import java.io.*; import java ...

  6. CentOS SSH安装与配置

    SSH 为 Secure Shell 的缩写,由 IETF 的网络工作小组(Network Working Group)所制定:SSH 为建立在应用层和传输层基础上的安全协议. 传 统的网络服务程序, ...

  7. 一张图让你看懂锻压、CNC、压铸、冲压四类工艺!

    (锻压+CNC+阳极.CNC+阳极.压铸+阳极.冲压+阳极手机外壳比较) 上图为一张雷达图,该图比较直观形象地描述了4大手机外壳工艺在6个维度(加工成本.CNC用量.加工周期.成品率.可设计性.外观质 ...

  8. 第一个C语言代码

    #include<stdio.h> void main() {     int g1,g2,g3,r1,r2,r3,n;     int m=0;     float ave;     i ...

  9. 拔高你的Java代码质量吧:推荐使用枚举定义常量(转)

    提高你的Java代码质量吧:推荐使用枚举定义常量 一.分析 常量的声明是每一个项目中不可或缺的,在Java1.5之前,我们只有两种方式的声明:类常量和接口常量.不过,在1.5版之后有了改进,即新增了一 ...

  10. WCF实例上下文

    实例上下文模式(IntanceContext Mode)表示服务端的服务实例与客户端的服务代理的绑定方式. 在WCF中有三种不同的实例上下文模式,单调(Per-Call)模式,会话(Per-Sessi ...