Response.Redirect与POST而不是Get?

我们有要求提交表单并保存一些数据,然后将用户redirect到非现场页面,但在redirect时,我们需要用POST提交表单,而不是GET。

我希望有一个简单的方法来完成这一点,但我开始认为没有。 我想我现在必须创build一个简单的其他页面,只是我想要的forms,redirect到它,填充表单variables,然后做一个body.onload调用脚本,只是调用document.forms [0] .submit( );

任何人都可以告诉我,如果有替代scheme? 我们可能需要稍后在项目中调整它,这可能会有点复杂,所以如果有一个简单的方法,我们可以做到这一切非所有的其他页面依赖,这将是太棒了。

无论如何,感谢所有的答复。

这样做需要了解HTTPredirect如何工作。 当你使用Response.Redirect() ,你发送一个响应(发送请求的浏览器)与HTTP状态代码302 ,告诉浏览器下一步去哪里。 根据定义,即使原始请求是POST ,浏览器也会通过GET请求来实现。

另一个select是使用HTTP状态代码307 ,它指定浏览器应该以原始请求的方式进行redirect请求,但要提示用户有安全警告。 要做到这一点,你会写这样的东西:

 public void PageLoad(object sender, EventArgs e) { // Process the post on your side Response.Status = "307 Temporary Redirect"; Response.AddHeader("Location", "http://example.com/page/to/post.to"); } 

不幸的是,这并不总是奏效。 不同的浏览器实现这个不同 ,因为它不是一个普通的状态码。

唉,与Opera和FireFox开发者不同的是,IE开发者从来没有阅读过这个规范,即使是最新的,最安全的IE7,也不会将任何警告或确认对话框的POST请求从域Aredirect到域B. Safari也以一种有趣的方式行事,而不会引发确认对话并执行redirect,它将抛弃POST数据, 从而有效地将307redirect转换为更常见的302。

所以,据我所知,实现像这样的唯一方法是使用Javascript。 我可以从头脑中想到两种select:

  1. 创build表单并将其action属性指向第三方服务器。 然后,向提交button添加一个单击事件,首先使用这些数据向服务器执行AJAX请求,然后允许将表单提交给第三方服务器。
  2. 创build表单发布到您的服务器。 提交表单时,向用户显示一个包含所有要传递的数据的表单的页面,全部隐藏在input中。 只是显示一条消息,如“redirect…”。 然后,将JavaScript事件添加到提交表单到第三方服务器的页面。

在这两个,我会select第二,有两个原因。 首先,它比第一个更可靠,因为Javascript不是必需的; 对于没有启用的用户,可以始终使隐藏表单的提交button可见,并指示他们在超过5秒的时间内按下该button。 其次,您可以决定将数据传输到第三方服务器; 如果您只是在处理表单的过程中进行处理,则会传递所有的后期数据,这并不总是您想要的。 假设它适用于所有的用户,307解决scheme也是如此。

希望这可以帮助!

你可以使用这个aproach:

 Response.Clear(); StringBuilder sb = new StringBuilder(); sb.Append("<html>"); sb.AppendFormat(@"<body onload='document.forms[""form""].submit()'>"); sb.AppendFormat("<form name='form' action='{0}' method='post'>",postbackUrl); sb.AppendFormat("<input type='hidden' name='id' value='{0}'>", id); // Other params go here sb.Append("</form>"); sb.Append("</body>"); sb.Append("</html>"); Response.Write(sb.ToString()); Response.End(); 

因为在客户端从服务器获得所有的html之后,事件onload会发生,触发表单提交并将所有数据发送到定义的postbackUrl。

HttpWebRequest用于这个。

回发时,创build一个HttpWebRequest到您的第三方并张贴表单数据,然后一旦完成,您可以Response.Redirect无论你想要的。

您获得了额外的优势,您不必命名所有的服务器控件来构build第三方,您可以在构buildPOSTstring时进行此翻译。

 string url = "3rd Party Url"; StringBuilder postData = new StringBuilder(); postData.Append("first_name=" + HttpUtility.UrlEncode(txtFirstName.Text) + "&"); postData.Append("last_name=" + HttpUtility.UrlEncode(txtLastName.Text)); //ETC for all Form Elements // Now to Send Data. StreamWriter writer = null; HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "POST"; request.ContentType = "application/x-www-form-urlencoded"; request.ContentLength = postData.ToString().Length; try { writer = new StreamWriter(request.GetRequestStream()); writer.Write(postData.ToString()); } finally { if (writer != null) writer.Close(); } Response.Redirect("NewPage"); 

但是,如果您需要用户从此表单中查看响应页面,则唯一的select是使用Server.Transfer,并且这可能无效。

这应该使生活更容易。 您可以在Web应用程序中轻松使用Response.RedirectWithData(…)方法。

 Imports System.Web Imports System.Runtime.CompilerServices Module WebExtensions <Extension()> _ Public Sub RedirectWithData(ByRef aThis As HttpResponse, ByVal aDestination As String, _ ByVal aData As NameValueCollection) aThis.Clear() Dim sb As StringBuilder = New StringBuilder() sb.Append("<html>") sb.AppendFormat("<body onload='document.forms[""form""].submit()'>") sb.AppendFormat("<form name='form' action='{0}' method='post'>", aDestination) For Each key As String In aData sb.AppendFormat("<input type='hidden' name='{0}' value='{1}' />", key, aData(key)) Next sb.Append("</form>") sb.Append("</body>") sb.Append("</html>") aThis.Write(sb.ToString()) aThis.End() End Sub End Module 

ASP.Net 3.5中的新东西是ASPbutton的“PostBackUrl”属性。 您可以将其设置为您想要直接发布到的页面的地址,并且单击该button时,而不是像正常一样回发到同一页面,而是发布到您指定的页面。 便利。 确保UseSubmitBehavior也设置为TRUE。

PostbackUrl可以设置在你的aspbutton上发布到不同的页面。

如果您需要在代码隐藏中执行此操作,请尝试Server.Transfer。

认为这可能是有趣的分享,heroku这是与附加组件提供商的SSO

在“kensa”工具的源代码中可以看到它如何工作的一个例子:

https://github.com/heroku/kensa/blob/d4a56d50dcbebc2d26a4950081acda988937ee10/lib/heroku/kensa/post_proxy.rb

在实践中可以看出,如果你转动的JavaScript。 示例页面源代码:

 <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Heroku Add-ons SSO</title> </head> <body> <form method="POST" action="https://XXXXXXXX/sso/login"> <input type="hidden" name="email" value="XXXXXXXX" /> <input type="hidden" name="app" value="XXXXXXXXXX" /> <input type="hidden" name="id" value="XXXXXXXX" /> <input type="hidden" name="timestamp" value="1382728968" /> <input type="hidden" name="token" value="XXXXXXX" /> <input type="hidden" name="nav-data" value="XXXXXXXXX" /> </form> <script type="text/javascript"> document.forms[0].submit(); </script> </body> </html> 

@马特,

您仍然可以使用HttpWebRequest,然后将收到的响应指向实际的输出stream响应,这将响应回给用户。 唯一的问题是任何相关的网站都会被打破。

不过,这可能工作。

这是我会做的:

将数据放入标准格式(不包含runat =“server”属性),并将表单的操作设置为发布到目标非现场页面。 提交之前,我会提交数据到我的服务器使用XmlHttpRequest并分析响应。 如果响应意味着您应该继续进行异地张贴,那么我(JavaScript)将继续该post,否则我会redirect到我的网站上的一个页面

在PHP中,您可以使用cURL发送POST数据。 有什么可比的.NET?

是的,HttpWebRequest,看到我的post下面。

我build议构build一个HttpWebRequest以编程方式执行您的POST,然后在读取响应(如果适用)后redirect。

不应该使用GET(和HEAD)方法来做任何有副作用的事情。 一个副作用可能是更新Web应用程序的状态,或者它可能会收取您的信用卡。 如果某个操作有副作用,则应该使用另一个方法(POST)。

所以,一个用户(或他们的浏览器)不应该对GET所做的事情负责。 如果由于GET而导致一些有害或昂贵的副作用,那将是Web应用程序的错误,而不是用户的错误。 根据规范,除非是GET或HEAD请求的响应,否则用户代理不能自动执行redirect。

当然,很多GET请求都会有一些副作用,即使它只是追加到日志文件中。 重要的是应用程序,而不是用户,应该对这些影响负责。

HTTP规范的相关部分是9.1.1和9.1.2和10.3 。

通常,你所需要的只是在这两个请求之间进行一些状态。 实际上有一个非常时髦的方式来做到这一点不依赖于JavaScript(认为<noscript />)。

 Set-Cookie: name=value; Max-Age=120; Path=/redirect.html 

有了那个cookie,你可以在下面的请求/redirect.html中检索name = value的信息,你可以在这个名字/值对string中存储任何types的信息,最多可以说4K的数据(典型的cookie限制)。 当然,你应该避免这种情况,而是存储状态码和标志位。

收到此请求后,您将回复该状态码的删除请求。

 Set-Cookie: name=value; Max-Age=0; Path=/redirect.html 

我的HTTP有点生疏,我一直在通过RFC2109和RFC2965来确定这是多么可靠,最好是我希望cookie往返一次,但似乎不可能,也是第三方的cookie如果您要重新定位到其他域名,可能会对您造成问题。 这仍然是可能的,但并不像您在自己的域中执行任何操作时那样轻松。

这里的问题是并发性,如果高级用户正在使用多个选项卡,并设法交错属于同一个会话的几个请求(这是非常不可能的,但不是不可能的),这可能会导致您的应用程序不一致。

这是进行HTTP往返的无脚本URL和JavaScript的<noscript />方法

我提供这个代码作为一个概念的教授:如果这个代码运行在你不熟悉的上下文中,我认为你可以计算出什么部分是什么。

这个想法是,当你redirect的时候你调用Relocate时,你重定位的URL调用GetState来获取数据(如果有的话)。

 const string StateCookieName = "state"; static int StateCookieID; protected void Relocate(string url, object state) { var key = "__" + StateCookieName + Interlocked .Add(ref StateCookieID, 1).ToInvariantString(); var absoluteExpiration = DateTime.Now .Add(new TimeSpan(120 * TimeSpan.TicksPerSecond)); Context.Cache.Insert(key, state, null, absoluteExpiration, Cache.NoSlidingExpiration); var path = Context.Response.ApplyAppPathModifier(url); Context.Response.Cookies .Add(new HttpCookie(StateCookieName, key) { Path = path, Expires = absoluteExpiration }); Context.Response.Redirect(path, false); } protected TData GetState<TData>() where TData : class { var cookie = Context.Request.Cookies[StateCookieName]; if (cookie != null) { var key = cookie.Value; if (key.IsNonEmpty()) { var obj = Context.Cache.Remove(key); Context.Response.Cookies .Add(new HttpCookie(StateCookieName) { Path = cookie.Path, Expires = new DateTime(1970, 1, 1) }); return obj as TData; } } return null; }