ASP.NET Web Forms跨站重定向时隐藏字段无法获取问题排查
我使用C# Web Forms,尝试从网站A重定向到同域的网站B(两站均通过Forms Authentication做密码保护),借助隐藏字段传递数据。但在网站B的登录后台代码中,无法从Request.Form NameValueCollection中提取隐藏字段值,访问请求表单键时还会出现空引用异常。
网站A代码
ASPX页面部分
<asp:LinkButton ID="redirectLink" runat="server" OnClick="RedirectLink_Click" OnClientClick="window.document.forms[0].target='_blank';">New Page - Website B </asp:LinkButton>
后台点击事件代码
Response.Clear(); StringBuilder sb = new StringBuilder(); sb.Append("<html>"); sb.Append("<body onload='submitForm()'>"); sb.AppendFormat("<form id='customForm' action='{0}' method='post'>", url + "/newpage.aspx?redirectPage=NewPage_Redirect"); sb.AppendFormat("<input type='hidden' name='Val1' value='{0}' id='Val1'>", Uri.EscapeDataString(value1)); sb.AppendFormat("<input type='hidden' name='Val2' value='{0}' id='Val2'>", Uri.EscapeDataString(value2)); sb.Append("</form>"); sb.Append("<script>"); sb.Append("function submitForm() {"); sb.Append("document.getElementById('customForm').submit();"); sb.Append("}"); sb.Append("</script>"); sb.Append("</body>"); sb.Append("</html>"); Response.Write(sb.ToString()); HttpContext.Current.ApplicationInstance.CompleteRequest();
网站B Page_Load代码
if ((Request.QueryString["redirectPage"] != null) && (Request.QueryString["redirectPage"].ToString() == "NewPage_Redirect")) { Response.Write(Request.Form["Val1"].ToString()); // NULL REFERENCE EXCEPTION Response.Write(Request.Form["Val2"].ToString()); }
排查过程更新
更新1
网站A生成的HTML代码如下,但网站B修改代码为Response.Write(Request.Form["Val1"])后不再报错,但Request.Form.AllKeys长度为0:
<html> <body onload='submitForm()'> <form id='customForm' action='https://websiteB.com/newpage.aspx?redirectPage=NewPage_Redirect' method='post'> <input type='hidden' name='Val1' value='abc123' id='Val1'> <input type='hidden' name='Val2' value='def456' id='Val2'> </form> <script> function submitForm() { document.getElementById('customForm').submit(); } </script> </body> </html>
更新2
通过浏览器工具发现代码生成的HTML并未出现在最终页面中,怀疑是ASP.NET Web Forms不允许嵌套表单的问题。
更新3
补充:ASPX页面中使用了LinkButton,代码片段已更新。
解决方案
1. 修复嵌套表单问题
ASP.NET Web Forms页面默认会生成一个runat="server"的服务端表单,你通过Response.Write输出的表单属于嵌套表单,浏览器会忽略嵌套表单,导致提交动作失效。
推荐使用客户端脚本动态创建表单(避免嵌套),直接在LinkButton的OnClientClick中处理提交逻辑:
<asp:LinkButton ID="redirectLink" runat="server" OnClick="RedirectLink_Click" OnClientClick="submitCustomForm(); return false;">New Page - Website B </asp:LinkButton> <script> function submitCustomForm() { // 创建独立表单元素 const form = document.createElement('form'); form.action = '<%= url %>/newpage.aspx?redirectPage=NewPage_Redirect'; form.method = 'POST'; form.target = '_blank'; // 添加隐藏字段Val1 const val1 = document.createElement('input'); val1.type = 'hidden'; val1.name = 'Val1'; val1.value = '<%= Uri.EscapeDataString(value1) %>'; form.appendChild(val1); // 添加隐藏字段Val2 const val2 = document.createElement('input'); val2.type = 'hidden'; val2.name = 'Val2'; val2.value = '<%= Uri.EscapeDataString(value2) %>'; form.appendChild(val2); // 提交并清理表单 document.body.appendChild(form); form.submit(); document.body.removeChild(form); } </script>
同时清空后台RedirectLink_Click方法的代码,无需再输出HTML内容。
2. 处理Forms Authentication跳转干扰
由于两站均启用Forms Auth,若用户未登录或会话过期,请求会被重定向到登录页,导致原POST表单数据丢失。需确保用户跳转前已通过网站B的身份验证,或在网站B登录页处理完登录后,将原请求的表单数据传递到newpage.aspx。
3. 网站B端空值校验优化
在newpage.aspx中先判断Request.Form是否包含目标键,再取值避免空引用:
if ((Request.QueryString["redirectPage"] != null) && (Request.QueryString["redirectPage"].ToString() == "NewPage_Redirect")) { if(Request.Form["Val1"] != null) { Response.Write(Request.Form["Val1"]); } if(Request.Form["Val2"] != null) { Response.Write(Request.Form["Val2"]); } }
内容的提问来源于stack exchange,提问作者IrishChieftain

