关于ajax跨域调用WCF服务的方法不少,通过我反复的代码测试,认为以下方法是最为简便的,固然也不能说别人的方法是错误的,下面就来上代码,WCF服务定义仍是延用上次的,如:javascript
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服务文件,文件内容:html
<%@ ServiceHost Language="C#" Debug="true" Service="WcfService1.AddService" %>
上面实现的是支持GET方法请求调用,下面就是配置WEB.CONFIG,使其支持跨域调用,注意我将standardEndpoints注释掉了,固然若是不注释也不会有什么影响,关键是bindings节点中的属性:crossDomainScriptAccessEnabled="true",以下:java
<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文件并添加以下的代码:web
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服务代码ajax
1.采用原生的XMLHttpRequest跨域调用WCF服务:json
//简单封装 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这个方案就无解:跨域
$("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调用:服务器
$("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来调用:app
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服务端已支持跨域调用:测试
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请求,采用的原理是上面我写的原始跨域调用方法)
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时,走了不少弯路,也尝试过不少方法,但最终仍是弄明白了,但愿你们能从这篇博文中受益,文中不足之处,敬请指出,谢谢!