我和我的同事花了很多时间来寻找这个答案,所以我想我应该分享这个自我回答的问题。
我有一个web服务(ASP。. NET 4.5)使用一个需要使用会话状态的方法。为了存档这一点,我用EnableSession=true修饰了该方法。这就是MS在这篇文章中建议的做法(见末尾的"代码块A")。
为了使web服务能够重用会话,它需要找到一个具有会话ID的cookie。该cookie在服务器端由web服务器自己在第一次调用该方法时创建和设置。为了在每次调用时重新发送此cookie, MS建议使用分配给web服务代理的"cookie容器",在调用之间保存并在每次调用时重用。(见末尾的"代码块B")。
只要你打算从服务器端调用web服务,这个方法就非常有效。我需要调用它从客户端使用jQuery ajax JSON Post调用(见"代码块C"在结束)。这段代码工作得很好。实际上,带有会话ID的cookie会自动传递给web服务。不需要饼干罐……只要客户端和web服务在同一域中。
如果客户端位于与web服务(domainb.com)不同的域(domaina.com)中,则带有会话id的cookie根本不会被传递。因此,对web服务的每次调用都被认为是第一次调用。
我在web配置中定义了以下标头,以允许跨域呼叫。
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
那么,缺少什么呢?
代码块A:带有装饰方法的Web Service
public class Util: WebService {
[ WebMethod(EnableSession=true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public int SessionHitCounter() {
if (Session["HitCounter"] == null) {
Session["HitCounter"] = 1;
}
else {
Session["HitCounter"] = ((int) Session["HitCounter"]) + 1;
}
return ((int) Session["HitCounter"]);
}
}
代码块B: Server Side Cookie Jar Solution
<script runat="server">
void EnterBtn_Click(Object Src, EventArgs E)
{
// Create a new instance of a proxy class for your XML Web service.
ServerUsage su = new ServerUsage();
CookieContainer cookieJar;
// Check to see if the cookies have already been saved for this session.
if (Session["CookieJar"] == null)
cookieJar= new CookieContainer();
else
cookieJar = (CookieContainer) Session["CookieJar"];
// Assign the CookieContainer to the proxy class.
su.CookieContainer = cookieJar;
// Invoke an XML Web service method that uses session state and thus cookies.
int count = su.PerSessionServiceUsage();
// Store the cookies received in the session state for future retrieval by this session.
Session["CookieJar"] = cookieJar;
// Populate the text box with the results from the call to the XML Web service method.
SessionCount.Text = count.ToString();
}
</script>
代码块C: Ajax调用
$.ajax({
type: "POST",
url: web_services_url + "/SessionHitCounter",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
alert(msg.d);
}
});
经过几个小时的思考和谷歌搜索,我的伴侣发现我们错过了
- 一个额外的头("Access-Control-Allow-Credentials")
- 将"Access-Control-Allow-Origin"上的"*"更改为正在调用web服务的特定域
- 在ajax调用(withCredentials)上添加一个额外的参数
这些是启用CORS所需的头文件
<add name="Access-Control-Allow-Origin" value="http://localhost:53710" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
<add name="Access-Control-Allow-Credentials" value="true" />
这是带有额外参数
的ajax调用$.ajax({
type: "POST",
xhrFields: { withCredentials: true },
url: web_services_url + "/SessionHitCounter",
data: "{}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg) {
alert(msg.d);
}
});