实现jquery.ajax及原生的XMLHttpRequest跨域调用WCF服务的方法

关于ajax跨域调用WCF服务的方法很多,经过我反复的代码测试,认为如下方法是最为简便的,当然也不能说别人的方法是错误的,下面就来上代码,WCF服务定义还是延用上次的,如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
namespace  WcfService1
{
     [ServiceContract]
     public  interface  IAddService
     {
 
         [OperationContract]
         [WebInvoke(Method= "GET" ,RequestFormat=WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json,BodyStyle=WebMessageBodyStyle.WrappedRequest)]
         int  Add2( int  a, int  b);
     }
}
 
 
namespace  WcfService1
{
     [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
     //[JavascriptCallbackBehavior(UrlParameterName="jsoncallback")] //不指定的时采用默认的callback回调参数
     public  class  AddService : IAddService
     {
         public  int  Add2( int  a,  int  b)
         {
             return  a + b;
         }
 
     }
}

创建一个WCF服务文件,文件内容:

1
<%@ ServiceHost Language="C#" Debug="true" Service="WcfService1.AddService" %>

上面实现的是支持GET方法请求调用,下面就是配置WEB.CONFIG,使其支持跨域调用,注意我将standardEndpoints注释掉了,当然如果不注释也不会有什么影响,关键是bindings节点中的属性:crossDomainScriptAccessEnabled="true",如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
< system.serviceModel >
   <!--<standardEndpoints>
     <webHttpEndpoint>
       <standardEndpoint crossDomainScriptAccessEnabled="true" />
     </webHttpEndpoint>
   </standardEndpoints>-->
   < serviceHostingEnvironment  multipleSiteBindingsEnabled="true" />
   < bindings >
     < webHttpBinding >
       < binding  crossDomainScriptAccessEnabled="true">
       </ binding >
     </ webHttpBinding >
   </ bindings >
   < behaviors >
     < serviceBehaviors >
       < behavior >
         <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->
         < serviceMetadata  httpGetEnabled="true"/>
         <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
         < serviceDebug  includeExceptionDetailInFaults="true"/>
       </ behavior >
     </ serviceBehaviors >
     < endpointBehaviors >
       < behavior  name="AddServiceBehavior">
         < enableWebScript  />
       </ behavior >
     </ endpointBehaviors >
   </ behaviors >
   < services >
     < service  name="WcfService1.AddService">
       < endpoint  address=""  binding="webHttpBinding" contract="WcfService1.IAddService" behaviorConfiguration="AddServiceBehavior" ></ endpoint >
     </ service >
   </ services >
</ system.serviceModel >

创建Global.asax文件并添加如下的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected  void  Application_BeginRequest( object  sender, EventArgs e)
{
     HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
     HttpContext.Current.Response.Cache.SetNoStore();
 
     EnableCrossDmainAjaxCall();
}
 
private  void  EnableCrossDmainAjaxCall()
{
     HttpContext.Current.Response.AddHeader( "Access-Control-Allow-Origin" , "*" );
 
     if  (HttpContext.Current.Request.HttpMethod ==  "OPTIONS" )
     {
         HttpContext.Current.Response.AddHeader( "Access-Control-Allow-Methods" ,
                       "GET, POST" );
         HttpContext.Current.Response.AddHeader( "Access-Control-Allow-Headers" ,
                       "Content-Type, Accept" );
         HttpContext.Current.Response.AddHeader( "Access-Control-Max-Age" ,
                       "1728000" );
         HttpContext.Current.Response.End();
     }
}

下面是实现WEB端跨域调用WCF服务代码

1.采用原生的XMLHttpRequest跨域调用WCF服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//简单封装
         var  $ =  function  (id) {
             return  document.getElementById(id);
         };
 
         function  getXMLHTTPRequest() {
             var  req =  false ;
             try  {
                 req =  new  XMLHttpRequest();
             catch  (err) {
                 try  {
                     req =  new  ActiveXObject( "Msxml2.XMLHTTP" );
                 catch  (err) {
                     try  {
                         req =  new  ActiveXObject( "Microsoft.XMLHTTP" );
                     catch  (err) {
                         req =  false ;
                     }
                 }
             }
             return  req;
         }
 
//以下为按钮的点击事件,我采用的同步调用,当然也可以采用回调方式,回调方式的话就需要在请求的URL中加入:callback=回调方法,然后再定义一个回调方法即可
         $( "btnGet" ).onclick =  function  () {
             var  querystr =  "a="  + $( "num1" ).value +  "&b="  + $( "num2" ).value;
             var  xmlhttp = getXMLHTTPRequest();
             xmlhttp.open( "GET" "http://localhost:30348/addservice.svc/Add2?"  + querystr,  false );
             xmlhttp.send();
             var  r = eval( "("  + xmlhttp.responseText +  ")" );
             $( "result" ).value = r.d;
         }

 

 

2.通过动态以JS方式请求WCF地址资源实现原始的跨域方法,虽然可以实现跨域调用,但只支持GET方式,如果需要支持POST这个方案就无解:

1
2
3
4
5
6
7
8
9
10
11
12
13
$( "btnGet" ).onclick =  function  () {
     var  querystr =  "a="  + $( "num1" ).value +  "&b="  + $( "num2" ).value;
     var  script =document.getElementById( "crossDomainScript_wcf" ) || document.createElement( "script" );
     script.type =  "text/javascript" ;
     script.id =  "crossDomainScript_wcf" ;
     script.src =  "http://localhost:30348/addservice.svc/Add2?callback=success_callback&"  + querystr;
     document.getElementsByTagName( "head" )[0].appendChild(script);
}
 
//回调方法
function  success_callback(data) {
     $( "result" ).value = data;
}

以下是POST调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$( "btnGet" ).onclick =  function  () {
     var  xmlhttp = getXMLHTTPRequest();
     xmlhttp.open( "POST" "http://localhost:30348/addservice.svc/Add2" true );
     xmlhttp.setRequestHeader( "Content-Type" "application/json" );
     xmlhttp.onreadystatechange =  function  () {
         alert(xmlhttp.status);
         if  (xmlhttp.readyState == 4) {
             if  (xmlhttp.status == 200) {
                 var  r = eval( "("  + xmlhttp.responseText +  ")" );
                 $( "result" ).value = r.d;
             }
         }
     };
     xmlhttp.send( '{"a":'  + $( "num1" ).value +  ',"b":'  + $( "num2" ).value +  '}' );
}

2.采用jQuery.ajax来调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var  jq = jQuery.noConflict();
jq( "#btnGet" ).click( function  () {
     jq.ajax( "http://localhost:30348/AddService.svc/Add2" , {
         type:  "get" ,
         dataType:  "jsonp" ,
         data:  'a='  + jq( "#num1" ).val() +  '&b='  + jq( "#num2" ).val(),
         success:  function  (data) {
             jq( "#result" ).val(data);
         },
         error:  function  (x, textStatus, errorThrown) {
             alert( "error:"  + textStatus);
         }
     });
});

其实可按正常方式直接调用,无需采用JSONP,因为WCF服务端已支持跨域调用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var  jq = jQuery.noConflict();
jq( "#btnGet11" ).click( function  () {
     jq.ajax( "http://localhost:30348/AddService.svc/Add2" , {
         type:  "GET" ,
         dataType:  "json" ,
         data:  'a='  + jq( "#num1" ).val() +  '&b='  + jq( "#num2" ).val(),
         success:  function  (data) {
             jq( "#result" ).val(data.d);
         },
         error:  function  (x, textStatus, errorThrown) {
             alert( "error:"  + textStatus);
         }
     });
});

  

当然传参时也可以用JSON的写法(注意POST与GET的JSON写法有所不同,POST时键值必需是严格的JSON字符串,GET时是一个JS对象),再此就不作说明

POST调用:(注意上述JQUERY.AJAX 采用JSONP+GET模式不适用于POST模式,因为经调试,发现采用JSONP模式,终始发起的是GET请求,采用的原理是上面我写的原始跨域调用方法)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var  jq = jQuery.noConflict();
jq( "#btnGet" ).click( function  () {
     jq.ajax( "http://localhost:30348/AddService.svc/Add2" , {
         type:  "POST" ,
         dataType:  "json" ,
         contentType:  "application/json" ,
         data:  '{"a":'  + jq( "#num1" ).val() +  ',"b":'  + jq( "#num2" ).val() +  '}' ,
         success:  function  (data) {
             jq( "#result" ).val(data.d);
         },
         error:  function  (x, textStatus, errorThrown) {
             alert( "error:"  + textStatus);
         }
     });
});

这里针对跨域再特别说明一下,若采用AJAX跨域调用时,会发送两次请求,第一次为OPTIONS,用于服务器进行预检,第二次才会发出真正的请求,这也就是为什么WCF服务的Global.asax需要添加EnableCrossDmainAjaxCall的原因。本人在研究跨域调用WCF时,走了很多弯路,也尝试过很多方法,但最终还是弄明白了,希望大家能从这篇博文中受益,文中不足之处,敬请指出,谢谢!

本文转自 梦在旅途 博客园博客,原文链接:http://www.cnblogs.com/zuowj/p/4820117.html  ,如需转载请自行联系原作者

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值