跨域场景下ASP.NET Session不共享问题及解决方案咨询
跨域场景下ASP.NET Session共享问题及解决方案
问题描述
我有一个ASP.NET Web应用,使用Session存储数据。流程为:应用调用外部应用,用户在外部应用选择值后,外部应用将值存入外部存储,再返回一个密钥到我方的End.aspx页面。我需要通过该密钥通知调用页面(customerpage.aspx)更新控件,因此将密钥存入Session,调用页面通过定时器轮询Ajax请求WebMethod检查Session值,存在值则停止定时器。
同IIS站点下运行正常,但当我方应用为独立站点http://site1,外部应用部署在Default Web Site的http://myvm/site2时,外部应用回调End.aspx会生成新SessionID,导致调用页面的WebMethod无法获取Session值(返回null)。Session采用SQL存储,相关代码如下:
End.aspx.cs 代码
public class End : System.Web.UI.Page { private void Page_Load(object sender, System.EventArgs e) { HttpContext.Current.Session["closed"] = true; } }
Customerpage.aspx.cs 代码
public partial class CustomerPagepopup : System.Web.UI.Page { [System.Web.Script.Services.ScriptMethod()] [System.Web.Services.WebMethod(EnableSession = true)] public static bool CheckClosed() { bool closed = false; if (HttpContext.Current.Session["closed"] != null) { HttpContext.Current.Session["closed"] = null; return true; } return closed; } }
customerpage.aspx 前端JS代码
function GetIfClosed() { $.ajax({ type: "POST", url: '<%= ResolveUrl("callingpage.aspx/CheckClosed") %>', data: "", contentType: "application/json; charset=utf-8", dataType: "json", success: function (msg) { // 处理结果 var process = msg.d if (process) { // 销毁定时器停止轮询 clearTimeout(timer); $("#cboxClose").click(); // 此处可添加用户提示 } else { // 继续轮询 TimerPoll(); } } }); }
解决方案
1. 手动传递SessionID到回调页面
外部应用回调End.aspx时,携带调用页面的SessionID作为参数:
- 调用外部应用的跳转链接中附加当前SessionID:
http://myvm/site2?sessionId=<%= Session.SessionID %> - 外部应用回调
End.aspx时,将该sessionId作为参数带回:http://site1/End.aspx?sessionId=xxx - 在
End.aspx的Page_Load中手动指定SessionID:
private void Page_Load(object sender, System.EventArgs e) { string sessionId = Request.QueryString["sessionId"]; if (!string.IsNullOrEmpty(sessionId)) { SessionIDManager manager = new SessionIDManager(); manager.SaveSessionID(HttpContext.Current, sessionId, out bool redirected, out bool cookieAdded); } HttpContext.Current.Session["closed"] = true; }
注意:需确保SQL Session配置允许跨站点使用相同SessionID,且Session未过期。
2. 改用独立状态标识替代Session
放弃Session传递状态,改用数据库或缓存存储唯一请求标识:
- 调用外部应用前,生成唯一请求ID(如
Guid.NewGuid().ToString()),存入缓存/数据库并设置过期时间,同时将该ID传递给外部应用 - 外部应用回调
End.aspx时,携带该请求ID,更新缓存/数据库中的状态为已完成 - 修改调用页面的轮询逻辑,根据请求ID查询状态而非Session
- 示例修改:
Customerpage.aspx跳转时生成请求ID:string requestId = Guid.NewGuid().ToString(); // 存入缓存,设置30分钟过期 Cache.Insert(requestId, false, null, DateTime.Now.AddMinutes(30), Cache.NoSlidingExpiration); // 传递给外部应用:http://myvm/site2?requestId=<%= requestId %>End.aspx回调时更新状态:string requestId = Request.QueryString["requestId"]; if (!string.IsNullOrEmpty(requestId)) { Cache[requestId] = true; }- 修改
CheckClosedWebMethod:[WebMethod(EnableSession = false)] public static bool CheckClosed(string requestId) { bool closed = false; if (HttpContext.Current.Cache[requestId] != null && (bool)HttpContext.Current.Cache[requestId]) { HttpContext.Current.Cache.Remove(requestId); return true; } return closed; } - 前端JS轮询时携带requestId:
var requestId = '<%= requestId %>'; // 页面加载时获取后端生成的ID function GetIfClosed() { $.ajax({ type: "POST", url: '<%= ResolveUrl("callingpage.aspx/CheckClosed") %>', data: JSON.stringify({ requestId: requestId }), contentType: "application/json; charset=utf-8", dataType: "json", success: function (msg) { var process = msg.d; if (process) { clearTimeout(timer); $("#cboxClose").click(); } else { TimerPoll(); } } }); }
3. 配置Cookie跨域共享(限同根域名)
若两个站点属于同根域名(如site1.myvm.com和site2.myvm.com),可配置Session Cookie的域属性:
- 在Web.config中设置Cookie域为根域名:
这种方式下两个站点会共享同一个Session Cookie,回调时可使用原SessionID。但如果是完全不同的域名(如<system.web> <sessionState mode="SQLServer" sqlConnectionString="YourSQLConnectionString" /> <httpCookies domain=".myvm.com" /> </system.web>site1.com和myvm.com),受浏览器同源策略限制,该方案不可行。
内容的提问来源于stack exchange,提问作者ARV
相关产品推荐
相关产品推荐

