关于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 ,如需转载请自行联系原作者