首页 > 代码库 > ASP.NET 中 POST 数据并跳转页面(译自 Redirect and POST in ASP.NET)
ASP.NET 中 POST 数据并跳转页面(译自 Redirect and POST in ASP.NET)
本文翻译自 Samer Abu Rabie 的 《Redirect and POST in ASP.NET》
简介
在实际项目中,我们会遇到这样一种应用场景:我们需要与第三方的应用程序通信,在某些特定的情形下,我们不得不使用 POST 请求而非 GET 请求传递信息。
背景
起初,这个问题看起来很简单,但实际并不是那样。我很努力地寻求这个问题的解决方法,仔细谷歌搜索之后发现并没有让我满意的较好解决方案。让我们先来看看向指定的目的URL发送数据(包括POST和GET)有哪些可选方法:
1. Response.Redirect: 这是一个被广泛应用的通用方法,但在ASP.NET中此方法只能进行GET传参,无法进行POST传参。
2. Server.Transfer: 这个方法确实是POST数据而非GET,但是很不幸,此方法只适用于请求源与目标地址在同一个应用程序中的情形;并且,当你使用此方法向第三方应用程序发送请求时,此方法并不奏效。
3. 使用 HttpWebRequest: 这是另一种从工作项目创建整个请求的方法,你可以指定内容,及内容类型,并把用“&”连接的数据写入一个串联的表单中,然后把内容转换为 byte 数组并通过调用 GetResponse() 方法提交。它会产生一个POST请求吗?是的,当然会。它会重定向到目的URL吗?不,它不会跳转。即使如此,你仍然可以将响应流通过浏览器渲染给用户,并且用户将会看到极好的目标页面,但是在这个渲染后的页面上的任何动作都会崩溃,因为你现在引用的是和请求相同的源地址——都在你的应用程序内。所以在渲染出的页面的任何回发请求都会响应为”404,页面未找到”。(为什么呢?一定要记得默认的PostBack特性即总是把请求回发给当前页面)。
4. 使用 WebClient: 这个方法是以上所列方法中我比较喜欢的一个,因为它够简单。创建一个WebClient 对象,赋给它目标Url地址,调用 UploadValues 方法——此方法需要一个 name-value 集合作为参数(此集合包含了你所有的POST数据),渲染响应流,向目标URL发起的POST请求很完美;但是像上一个方法一样,你又遇到了相同的情形,引用与请求是相同的源地址,所以任何POST请求都会报404错误。
5. HTML Submit button with POST form: 这是向任何一个 URL POST 数据的标准方法,无论是你本地的应用程序还是第三方应用,但是这将限制你有一个提交按钮,比如:<input type="submit"/>,当然这个按钮将无法执行任何服务器端事件,并且你不得不以某种方式按下这个按钮。
注意:如果你有其他方法,请继续使用,我已经将我所见全盘托出。
现在,让我们来想象一下,我有一个 Response.Redirect 方法,并且我可以通过POST方式传递一个数据集合,是不是很炫?我想这肯定棒极了~
现在,整个目标是,拥有一个方法能提交一个数据集合,并且所有数据都是以POST方式提交到指定URL的。
使用代码
本文中我附上了一个文件,里面包含了一个叫作“HttpHelper”的类。这个类只有两个方法:一个私有方法 PreparePOSTForm 和一个公共方法 RedirectAndPOST。当然,你将只能使用那个公共方法;那个私有方法只是为了封装公共方法所需的功能。
下面展示具体的使用方法:
NameValueCollection data = http://www.mamicode.com/new NameValueCollection();
data.Add("v1", "val1");
data.Add("v2", "val2");
HttpHelper.RedirectAndPOST(this.Page, "http://DestUrl/Default.aspx", data);
v1 和 v2 将会以 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));
}
如你所见,我们用一个包含了多个隐藏域的 HTML 表单来保存将要进行 POST 的数据,以及一个包含了提交(Submit)操作的 Javascript 脚本标签用于触发回发操作,脚本将在回发前执行。
下面是 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=http://www.mamicode.com/"" + 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();
}
真的是非常简单的代码……对于每一个想提交的数据, 我们创建了一个隐藏域来保存它的值,我们添加了必要的脚本,通过 vPostForm.submit() 来使表单完成自动提交操作。
可以到本文顶部的原文中下载演示代码,也可以点击这里下载:HttpHelper