Querystring 末尾被追加 <!DOCTYPE html PUBLIC
支付老李
结论
<!DOCTYPE html PUBLIC ...> 不是 Querystring 的一部分,而是 ASPX 页面继续渲染后输出的 HTML。Response.Write() 只会向响应正文写入字符串,不会终止页面生命周期,所以最终响应可能变成:
REDIRECT=http://www.mywebsite.com/gateway/finalStatus.aspx?Result=Success&Amount=12345<!DOCTYPE html PUBLIC ...>
支付网关会把 REDIRECT= 后面的所有内容当作跳转地址,HTML 文档声明也就被拼进了 URL。
回调接口应该只输出网关要求的 REDIRECT=...,随后立即终止响应,避免继续渲染 ASPX 页面内容。
推荐实现
先对参数进行 URL 编码,再清空已有响应并输出纯文本:
using System;
using System.Web;
string url =
"http://www.mywebsite.com/gateway/finalStatus.aspx"
+ "?Result=" + HttpUtility.UrlEncode(Result)
+ "&Amount=" + HttpUtility.UrlEncode(Amount);
Response.Clear();
Response.ContentType = "text/plain";
Response.ContentEncoding = System.Text.Encoding.UTF8;
Response.Write("REDIRECT=" + url);
Response.End();
Response.End() 会立即结束响应,但在 ASP.NET Framework 中可能触发 ThreadAbortException。这是已知行为。如果日志系统会把这个异常记为错误,可以改用专门的 HTTP Handler 处理回调。
更稳妥的做法:使用独立 Handler
支付网关回调通常用不到页面控件和 HTML,更适合使用 .ashx:
using System.Text;
using System.Web;
public class PaymentRedirectHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
string result = context.Request["Result"];
string amount = context.Request["Amount"];
string url =
"http://www.mywebsite.com/gateway/finalStatus.aspx"
+ "?Result=" + HttpUtility.UrlEncode(result)
+ "&Amount=" + HttpUtility.UrlEncode(amount);
context.Response.Clear();
context.Response.ContentType = "text/plain";
context.Response.ContentEncoding = Encoding.UTF8;
context.Response.Write("REDIRECT=" + url);
}
public bool IsReusable
{
get { return false; }
}
}
Handler 没有 ASPX 页面的 HTML 渲染过程,不会自动追加 DOCTYPE、表单或其他标签。
为什么不能使用 Response.Redirect
下面的写法含义不同:
Response.Redirect("REDIRECT=http://www.mywebsite.com/...");
Response.Redirect() 会向浏览器发送 HTTP 302 响应,并把参数作为 Location 地址处理。REDIRECT=http://... 通常不是有效的目标 URL。
如果支付网关要求的格式确实是:
REDIRECT=http://www.mywebsite.com/...
它要求的就是响应正文协议,应该通过 Response.Write() 输出,而不是调用 Response.Redirect()。
注意事项
- 确认 ASPX 文件没有输出
<!DOCTYPE ...>、空格、换行或其他静态内容。 - 不要在
Response.Write()之后继续输出日志、调试文本或 HTML。 Result等字符串必须经过HttpUtility.UrlEncode(),否则其中的&、+、空格等字符可能破坏 Querystring。- 金额最好使用固定格式生成,避免服务器的区域设置把小数点变成逗号。
- 如果支付网关对响应内容有严格要求,还要确认它规定的字符编码、换行规则和 HTTP 状态码。
CompleteRequest()只会让 ASP.NET 跳到管道末尾,不能保证立即停止 ASPX 页面的后续渲染,因此不能单独用它解决 HTML 被追加的问题。
备注:内容仅供参考。
