在 ASP.NET 中实现非 ASP.NET Post 请求






4.33/5 (4投票s)
如何在 ASP.NET 页面中包含多个 form 标签。
在与 Web 上的一些资源交互时,有时会收到一小段 HTML 代码。 例如,要在您的网站上插入一个 PayPal 按钮,PayPal 会提供 HTML 代码,如下所示。
<form action="https://www.paypal.com/cgi-bin/webscr" method="post">
<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" name="business" value="bob@domain.com">
<input type="hidden" name="lc" value="US">
<input type="hidden" name="item_name" value="Widget">
<input type="hidden" name="amount" value="100.00">
<input type="hidden" name="currency_code" value="USD">
<input type="hidden" name="bn"
value="PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest">
<input type="image"
src="https://www.paypal.com/en_US/i/btn/btn_buynow_LG.gif"
border="0" name="submit" alt="">
<img alt="" border="0"
src="https://www.paypal.com/en_US/i/scr/pixel.gif"
width="1" height="1">
</form>
插入 PayPal 按钮的 HTML 代码
此代码片段定义了一个 <form>
标签和几个 <input>
标签,包括一个提交按钮。 单击提交按钮时,表单中的项目将被发布到 <form>
标签的 action
属性中指定的 URL。 然后,目标 URL 可以检查这些 <input>
标签的值并执行所需的操作。
但是,您可能会发现此类代码片段在插入到 ASP.NET 页面时无法正常工作。 主要问题是 ASP.NET 页面已经定义了一个表单。 为了使 ASP.NET 的回发机制正常工作,所有控件都放置在一个 <form>
标签内。 由于 HTML 不允许嵌套 <form>
标签,因此将如上所示的代码插入到 ASP.NET 页面中会导致问题。
有很多可能的方法来解决这个问题。 让我先从几个我认为不太理想的方法开始。 第一种方法是简单地将插入的 HTML 代码移动到 ASP.NET 表单的结束 </form>
标签之后。 虽然您不能嵌套 <form>
标签,但在同一页面上包含多个非嵌套 <form>
标签是可以的。
这样做的结果是,页面现在有两个单独的 <form>
标签,您会发现这通常可以按预期工作。 但是,这里的问题是您会失去一些 ASP.NET 功能。 例如,插入的 HTML 代码位于您的 ASP.NET 表单之后,因此它实际上并未嵌入到您的 ASP.NET 内容中。 而且,如果您使用的是母版页,则无法在内容页中执行此操作,因为内容页中的所有内容都放置在母版页中定义的 <form>
标签内。
第二种方法有点丑陋的 hack,如下所示
protected void btnPayPal_Click(object sender, ImageClickEventArgs e)
{
System.Web.HttpContext.Current.Response.Clear();
System.Web.HttpContext.Current.Response.Write("<html><head>");
System.Web.HttpContext.Current.Response.Write("</head><body " +
"onload='document.form1.submit()'>");
System.Web.HttpContext.Current.Response.Write("<form " +
"action='https://www.paypal.com/cgi-bin/webscr' " +
"name='form1' method='post'>");
System.Web.HttpContext.Current.Response.Write("<input " +
"type='hidden' name='cmd' value='_xclick'>");
System.Web.HttpContext.Current.Response.Write(
"<input type='hidden' name='business' " +
"value='bob@domain.com'>");
System.Web.HttpContext.Current.Response.Write(
"<input type='hidden' name='lc' value='US'>");
System.Web.HttpContext.Current.Response.Write(
"<input type='hidden' name='item_name' value='Widget'>");
System.Web.HttpContext.Current.Response.Write(
"<input type='hidden' name='amount' value='100.00'>");
System.Web.HttpContext.Current.Response.Write(
"<input type='hidden' name='currency_code' value='USD'>
System.Web.HttpContext.Current.Response.Write(
"<input type='hidden' name='bn' " +
"value='PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest'>
System.Web.HttpContext.Current.Response.Write(
"<input type='image' " +
"src='https://www.paypal.com/en_US/i/btn/btn_buynow_LG.gif' " +
"border='0' name='submit' alt=''>");
System.Web.HttpContext.Current.Response.Write("<img alt='' border='0' " +
"src='https://www.paypal.com/en_US/i/scr/pixel.gif' " +
"width='1' height='1'>");
System.Web.HttpContext.Current.Response.Write("</form>");
System.Web.HttpContext.Current.Response.Write("</body></html>");
System.Web.HttpContext.Current.Response.End();
}
执行非 ASP.NET 回发的丑陋 hack
此代码响应用户单击名为 btnPayPal
的按钮而运行。 它动态创建一个 HTML 页面,然后将其提供给用户的浏览器。 创建的页面复制了我们第一个列表中的表单,但在页面的 <body>
标签中添加了一个 onload
属性,该属性使表单在加载后立即提交,并且用户永远不会看到此临时页面。
这绝对是一个丑陋的 hack。 而且,虽然它可以工作,但它存在一些问题。 主要问题是,如果在运行代码后,用户按下浏览器中的“后退”按钮,浏览器将重新加载此临时页面,这将导致再次发生相同的操作,这绝对有可能导致一些讨厌的问题。
在探索了这两种选择之后,我最终选择了第三种方法,这种方法似乎更简单,并且似乎没有任何重大问题。 从 ASP.NET 2.0 开始,按钮具有一个名为 PostBackUrl
的属性,该属性可用于使该按钮回发到包含该按钮的页面以外的页面。
乍一看,这似乎没有帮助。 ASP.NET 按钮旨在回发到 ASP.NET 页面。 而且,我想回发到非 ASP.NET 页面。 但是,在两种情况下,回发机制是相同的。 如果我们回发到非 ASP.NET 页面,我们将发送大量附加数据——我们 ASP.NET 表单上的所有表单项目——到目标页面。 但是,只要没有冲突的项目名称(这不太可能),这实际上不是问题。
有了这些知识,我们就可以重写我们的原始代码块并将其插入到 ASP.NET 页面中。
<input type="hidden" name="cmd" value="_xclick">
<input type="hidden" name="business" value="bob@domain.com">
<input type="hidden" name="lc" value="US">
<input type="hidden" name="item_name" value="Widget">
<input type="hidden" name="amount" value="100.00">
<input type="hidden" name="currency_code" value="USD">
<input type="hidden" name="bn"
value="PP-BuyNowBF:btn_buynow_LG.gif:NonHostedGuest">
<asp:ImageButton ID="ImageButton1" runat="server"
ImageUrl="https://www.paypal.com/en_US/i/btn/btn_buynow_LG.gif"
PostBackUrl="https://www.paypal.com/cgi-bin/webscr" />
插入到 ASP.NET 页面中的 PayPal 按钮
我从这段代码中删除了 <form>
标签。 我们不需要它,因为我们的 ASP.NET 表单已经定义了一个 <form>
标签。 我删除了 <img>
和提交 <input>
标签,并将它们替换为 ImageButton
。 我将 ImageButton
的 ImageUrl
属性设置为与原始代码中使用的相同 PayPal 按钮图像,最后,我将 PostBackUrl
属性设置为原始 HTML 代码中 <form>
标签的 action
属性中指定的 URL。
结果是,当单击 ImageButton
时,整个表单将发布到 PayPal URL。 正如我之前提到的,这包括我们所有的其他 ASP.NET 值,包括页面的 ViewState 数据。 但是,ViewState 数据已加密,并且 PayPal 站点只会查看它感兴趣的值。
结果是,我能够在 ASP.NET 表单中的任何位置插入 PayPal 按钮,我仍然能够使用所有 ASP.NET 功能,PayPal 获得了完成其工作所需的所有值,并且如果用户碰巧从 PayPal 站点点击浏览器的“后退”按钮,也不会出现任何奇怪的问题。