本文翻译自 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 = 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=\"" + 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

最新文章

  1. 涵涵和爸爸习惯养成进度表(二)(May 30 - )
  2. 基于PHP的AJAX学习笔记(教程)
  3. 使用springMVC实现文件上传和下载之环境配置与上传
  4. PHP strlen() 函数
  5. Linux Device Driver 3th 中的一些坑
  6. 通过yum升级CentOS/RHEL最小化安装
  7. Shell 整数比较、字符串比较
  8. Android开发学习之路--UI之基本布局
  9. Myeclipse+selenium2.0+Junit+TestNg环境搭建
  10. 【心得】Lattice后端使用经验小结(ECP5UM,DDR3,Diamond3.10,Reveal逻辑分析)
  11. DZY Loves Math 系列详细题解
  12. CentOS7更改运行级别
  13. 《程序员的自我修养》读书笔记——系统调用、API
  14. django(六)之ORM数据库操作
  15. work flow 工作流程
  16. pdo连接数据
  17. 【MySQL】查询时强制区分大小写的方法
  18. Log4j记录日志使用方法
  19. Map常用集合遍历
  20. HDU - 1465 不容易系列之一(错排)

热门文章

  1. MFC工具栏设计
  2. 类的super
  3. 前端 javascript 数据类型 数字
  4. 机器学习算法(优化)之二:期望最大化(EM)算法
  5. Python:6种标准数据类型
  6. CentOS忘记用户名或者密码解决办法
  7. Writing a device driver for Windows
  8. 2017 计蒜之道 初赛 第三场 D. 腾讯狼人杀 (点边都带权的最大密度子图)
  9. 关于jQuery获得表单radio类型输入框的选中值
  10. Linux查看端口占用情况,并强制释放占用的端口