CORS 环境中 jQuery AJAX 调用之间的 ASP NET 会话

Posted

技术标签:

【中文标题】CORS 环境中 jQuery AJAX 调用之间的 ASP NET 会话【英文标题】:ASPNET Session between jQuery AJAX calls in a CORS enviroment 【发布时间】:2013-07-27 22:21:55 【问题描述】:

使用VS2012,框架4.5

我有一个简单的 webapp,只有一个 WebService.asmx 文件。运行项目会发布这 2 个 webmethod,SetDataGetData,这是 C# 代码:

[WebService(Namespace = "http://mydomain.com/")]
[System.Web.Script.Services.ScriptService]
public class WebService: System.Web.Services.WebService 

  [WebMethod(EnableSession=true)]
  [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
  public string SetData() 
      HttpContext.Current.Session["someData"] = "xxxxxxxxx";
      return "";
  

  [WebMethod(EnableSession = true)]
  [ScriptMethod(ResponseFormat = ResponseFormat.Json)]
  public string GetData() 
      if (HttpContext.Current.Session["someData"] == null)
          return "Session NULL";
      else
          return HttpContext.Current.Session["someData"].ToString();
  

web.config 设置为启用 CORS,aspNetCompatibilityEnabled 设置为启用会话共享

<system.webServer>
  <httpProtocol>
    <customHeaders>
      <add name="Access-Control-Allow-Origin" value="null" />
      <add name="Access-Control-Allow-Headers" value="Content-Type" />
      <add name="Access-Control-Allow-Credentials" value="true" />
    </customHeaders>
  </httpProtocol>
</system.webServer>

<system.serviceModel>
  <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
</system.serviceModel>

所以项目运行良好。现在我想从一个简单的 html 页面使用这两种方法(HTML NOT 是 ASPNET 项目的一部分,只是一个 HTML 文件......因此是 CORS 问题) 这是 HTML 代码(为简单起见,省略了 HTML 标记,但它只是一个空页面):

<script type="text/javascript">
    $(document).ready(function() 
        //jQuery.support.cors = true;
        $.ajax(
            type: "POST",
            url: "http://localhost:62776/WebService.asmx/SetData",
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            success: function(msg) 
                alert('SetData OK');
                $.ajax(
                    type: "POST",
                    url: "http://localhost:62776/WebService.asmx/GetData",
                    contentType: "application/json; charset=utf-8",
                    dataType: "json",
                    //async: true, -- makes no difference
                    //beforeSend: function(xhr)
                    //    xhr.withCredentials = true;
                    //,
                    success: function(msg) 
                        alert('GetData: ' + msg.d);
                    ,
                    error: function(e)
                        alert("GetData: Unavailable");
                    
                );

            ,
            error: function(e)
                alert("SetData: Unavailable");
            
        );
    );
</script>

运行 HTML 页面给我SetData OK,然后是GetData: Session NULL,但我想要GetData: xxxxxx

所以我的问题是,如何在 CORS 调用之间访问相同的 Session Object

我还尝试启用身份验证,认为 ASPNET AUTH COOKIES 会以某种方式在 AJAX 调用之间保持正确的会话 ID,但它不起作用。有一种可能的方法使用 SOAP 信封来验证每个 AJAX 调用并发送会话信息,但这似乎有点过头了。

【问题讨论】:

你看过IRequireSessionState了吗? msdn.microsoft.com/en-us/library/… 【参考方案1】:

您需要设置 withCredentials 这意味着客户端希望发送隐式“东西”(包括 cookie):

http://brockallen.com/2012/12/15/cors-and-windows-authentication/

此外,鉴于您需要允许“凭据”,服务器必须使用 Access-Control-Allow-Origin 响应特定来源请求——它不能使用“*”。

【讨论】:

谢谢,已经试过了,还是不行。这里的问题不是身份验证。我也知道你不能同时拥有 Origin=* 和 Credentials 。 Origin=* 是唯一的方法,因为 CORS 的来源是未知的,就像你发布了一个开放的 API,你不知道它会从哪些域访问。 嗯,我唯一能想到的就是发出cookie的请求也需要withCredentials。【参考方案2】:

您是否尝试过添加到您的 web.config 文件

<webServices>
  <protocols>
    <add name="HttpGet"/>
    <add name="HttpPost"/>
  </protocols>
</webServices>

或将以下代码添加到您的网络方法中:

[ScriptMethod(UseHttpGet = true)]
public string HelloWorld()

   return "Hello World";

用它来调用你的服务(javascript):

function SendAjaxRequest(url) 

var xmlhttp = "";

if (window.XMLHttpRequest) 
    xmlhttp = new XMLHttpRequest();
 else 
    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");


xmlhttp.open("GET", url, false);
xmlhttp.onreadystatechange = function () 
    //when response is ready
    if (xmlhttp.readyState == 4 && xmlhttp.status == 200) 
        var rspText = xmlhttp.responseText;
        if (rspText != undefined) 
            // here is the response
            var json = JSON.parse(rspText);
        
    


   xmlhttp.send(null);

如果您注意到返回的数据会被包含在标签中以将其删除并仅获取数据,请使用此函数:

function TrimXmlTag(start, responseText) 

   var from = responseText.indexOf(start),
       remaining = responseText.substring(from, responseText.length - 9);

   return remaining;

只需更改这一行:

 var json = JSON.parse(TrimXmlTag("[",rspText));

希望对你有帮助。

【讨论】:

@Nick:我在通过 $.ajax() 调用 asp.net webservice 时遇到了同样的问题,尝试将其添加到您的 webservice 方法 HttpContext.Current.Response.AppendHeader("Access-Control-Allow-起源”, ”*”); ...在弄乱它之后,我只是使用 XmlHttpRequest 解决了它 @marverick 我不认为new ActiveXObject("Microsoft.XMLHTTP"); 可以在 Linux 和 Macs 浏览器上运行。这个想法是在任何平台(Win / Mac/ *nix / ios / android / BB10 / etc)上通过标准 HTML5 访问网络服务

以上是关于CORS 环境中 jQuery AJAX 调用之间的 ASP NET 会话的主要内容,如果未能解决你的问题,请参考以下文章