实现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时,走了很多弯路,也尝试过很多方法,但最终还是弄明白了,希望大家能从这篇博文中受益,文中不足之处,敬请指出,谢谢!
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步