65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET 中的重定向和 POST

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.78/5 (83投票s)

2009 年 6 月 22 日

CPOL

5分钟阅读

viewsIcon

678004

downloadIcon

11349

本文介绍了一种简单的解决方案,用于将数据 POST 并重定向到外部 URL。

引言

最近,我遇到一种情况,我有一个应用程序需要与第三方支付应用程序通信,在某个时候,我需要使用 POST 而不是 GET 方法将信息发送到该第三方应用程序。

背景

好吧,一开始听起来很简单,但事实并非如此。我对此进行了大量研究,并进行了密集的 Google 搜索,但一直没有找到令我满意的解决方案。让我们先看看提交数据(POST 或 GET)到目标 URL 的选项:

  1. Response.Redirect:此方法被广泛使用且很常见,但在 ASP.NET 中它只使用 GET 方法,无法通过它进行 POST。
  2. Server.Transfer:此方法执行 POST 而不是 GET,但是……不幸的是,它只在源应用程序和目标应用程序相同时才有效;因此,如果您向第三方应用程序发送请求,这将不起作用……太糟糕了 :S
  3. 使用 HttpWebRequest:这是另一种从头开始创建整个请求的方法,您指定内容、内容类型,将数据连接成“&”的形式,然后转换为字节,并通过调用 GetResponse() 方法提交请求……它执行 POST 吗?是的,它执行了!!!它会重定向到目标 URL 吗?不,它没有!!!即便如此,您仍然会在浏览器中为用户呈现响应,用户将完美地看到目标页面,但是在此页面上的任何操作都将以泪告终,因为您仍然在引用请求的同一个源……也就是您的应用程序……因此,该页面上的任何回发都将显示 404……页面未找到。(为什么?还记得默认的回发行为始终是针对页面本身的……所以 ;)。)
  4. 使用 WebClient:此方法是我列出选项中最喜欢的……因为它很简单……创建一个 WebClient 对象,指定目标 URL,调用 UploadValues 方法,该方法接受一个名称-值集合(其中包含您的所有 POST 数据),呈现响应,一切都完美地 POST 到目标 URL;但与前一种选择一样,您仍然处于同一位置,即您的应用程序……因此,该页面上的任何回发都将显示 404……页面未找到。
  5. 带有 POST 表单的 HTML 提交按钮:好吧,这是将 POST 数据发送到任何 URL 的标准方法,无论是您自己的应用程序还是第三方应用程序,但是这会限制您必须有一个提交按钮,例如 <input type="submit"/>,当然,它不会为您执行任何服务器端事件!!!而且在某种程度上,您最终必须在某个时候按下该按钮……别无他法……太糟糕了 :S

注意:如果您有其他方法……请保留…… ;) 我已经受够了我看到的东西了!

现在,让我们想象一下,我有一个 Response.Redirect 方法,我向它提供一个数据集合,并告诉它执行 POST 方法而不是 GET 方法……那不是很棒吗?我认为那会很棒……真的只是一个小愿望!:)

现在,这才是重点,有一个方法,我向其提供一个要提交到目标 URL 的数据集合,然后所有数据都以重定向的方式 POST 过去

使用代码

我在此文章中附带了一个文件,其中包含一个名为 HttpHelper 的类。该类只有两个方法:一个私有方法 PreparePOSTForm 和一个公共方法 RedirectAndPOST。当然,您将只使用公共方法;私有方法只是用于封装公共方法所需的功能……没关系……您只需要调用公共方法,然后就完成了!

下面显示了该方法的使用方式

NameValueCollection data = new NameValueCollection();
data.Add("v1", "val1");
data.Add("v2", "val2");
HttpHelper.RedirectAndPOST(this.Page, "http://DestUrl/Default.aspx", data);

v1v2 将会以重定向的方式 POST 到目标 URL;重定向意味着您将被重定向到目标 URL,并且在那里的任何回发都将成功发生,因为您已完全转移到那里。

但是,RedirectAndPOST 方法是如何实现所需技巧的呢?!

/// <summary>
/// POST data and Redirect to the specified url using the specified page.
/// </summary>
/// <param name="page">The page which will be the referrer page.</param>
/// <param name="destinationUrl">The destination Url to which
/// the post and redirection is occuring.</param>
/// <param name="data">The data should be posted.</param>
/// <Author>Samer Abu Rabie</Author>

public static void RedirectAndPOST(Page page, string destinationUrl, 
                                   NameValueCollection data)
{
//Prepare the Posting form
string strForm = PreparePOSTForm(destinationUrl, data);
//Add a literal control the specified page holding 
//the Post Form, this is to submit the Posting form with the request.
page.Controls.Add(new LiteralControl(strForm));
}

正如您所见……我们准备了 POST 表单,这是一个 HTML 表单,其中包含您 POST 数据的隐藏字段和一个脚本标签,该标签包含表单的提交操作……它将在回发后立即执行。

以下是 PreparePOSTForm 方法的代码

/// <summary>
/// This method prepares an Html form which holds all data
/// in hidden field in the addetion to form submitting script.
/// </summary>
/// <param name="url">The destination Url to which the post and redirection
/// will occur, the Url can be in the same App or ouside the App.</param>
/// <param name="data">A collection of data that
/// will be posted to the destination Url.</param>
/// <returns>Returns a string representation of the Posting form.</returns>
/// <Author>Samer Abu Rabie</Author>

private static String PreparePOSTForm(string url, NameValueCollection data)
{
    //Set a name for the form
    string formID = "PostForm";
    //Build the form using the specified data to be posted.
    StringBuilder strForm = new StringBuilder();
    strForm.Append("<form id=\"" + formID + "\" name=\"" + 
                   formID + "\" action=\"" + url + 
                   "\" method=\"POST\">");

    foreach (string key in data)
    {
        strForm.Append("<input type=\"hidden\" name=\"" + key + 
                       "\" value=\"" + data[key] + "\">");
    }

    strForm.Append("</form>");
    //Build the JavaScript which will do the Posting operation.
    StringBuilder strScript = new StringBuilder();
    strScript.Append("<script language="'javascript'">");
    strScript.Append("var v" + formID + " = document." + 
                     formID + ";");
    strScript.Append("v" + formID + ".submit();");
    strScript.Append("</script>");
    //Return the form and the script concatenated.
    //(The order is important, Form then JavaScript)
    return strForm.ToString() + strScript.ToString();
}

代码非常简单……对于您想要 POST 的每个键值,我们创建一个隐藏字段,创建一个表单,然后添加必要的脚本来自动提交,通过 JavaScript 代码调用 vPostForm.submit()

关注点

为什么将生成的表单和脚本放入一个 Literal 控件并将该控件添加到请求的页面中?! 嗯……这个想法基本上是创建一个能够自动提交值而无需触发的表单……我们创建了该表单及其脚本……现在我们需要让它运行……我们通过将这段代码添加到 Literal 控件来实现,该控件的内容将被显示,不带任何标签!是的……不带标签……这就是技巧……所以表单和脚本将在请求中显示。现在,由于我们正在回发到同一页面……内容(我们的表单和脚本)将成功运行。当它运行时,提交过程发生,并且我们的数据与指定的目标 URL 发生自动回发 :)

如果有人问我这个解决方案的缺点,我会说也许有一个缺点……那就是如果客户端在浏览器中禁用了 JavaScript……那么这个将不起作用。我还没有尝试过……但我预计是这样……对我来说,这是一个重要的进步和一个重要的解决方案,它极大地帮助我解决了许多问题 :)

我希望我的解释足够清晰……因为它需要对 ASP.NET 页面生命周期以及对页面的回发概念有深入的理解。

历史

  • 创建了文章,版本 1.0。
© . All rights reserved.