我希望有一种简单的方法可以完成此操作,但我开始认为没有。我想我现在必须创建一个简单的其他页面,仅包含我想要的表单,重定向到该页面,填充表单变量,然后对仅调用document.forms [0] .submit()的脚本执行body.onload调用);
谁能告诉我是否还有其他选择?我们可能会在项目的稍后部分进行调整,这可能会变得有些复杂,因此,如果有一个简单的方法,我们可以完成所有非其他页面相关的操作,这将是非常棒的。
感谢您的任何答复。
#1 楼
为此,需要了解HTTP重定向的工作方式。当使用Response.Redirect()
时,您将使用HTTP状态码302发送响应(向发出请求的浏览器),该响应告诉浏览器下一步该去哪里。根据定义,即使原始请求是GET
,浏览器也会通过POST
请求来实现。另一个选项是使用HTTP状态代码307,该代码指定浏览器应发出重定向请求。以与原始请求相同的方式,但是向用户提示安全警告。为此,您可以这样编写:
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请求从域A重定向到域B,而不会出现任何警告或确认对话框! Safari的运行方式也很有趣,虽然它不会引发确认对话框并执行重定向,但它会丢弃POST数据,从而有效地将307重定向更改为更常见的302。
因此,据我所知,实现这种功能的唯一方法是使用Javascript。我想到了两个选项:
创建表单并将其
action
属性指向第三方服务器。然后,在“提交”按钮上添加一个click事件,该事件首先使用数据对服务器执行AJAX请求,然后允许将表单提交给第三方服务器。创建表单以将其发布到服务器。提交表单后,向用户显示一个包含表单的页面,其中包含您要传递的所有数据,所有数据都在隐藏的输入中。只需显示诸如“正在重定向...”之类的消息即可。然后,在页面上添加一个javascript事件,以将表单提交给第三方服务器。
由于两个原因,我会选择第二个。首先,它比第一种更可靠,因为它不需要Java脚本即可工作。对于未启用该功能的用户,您始终可以使隐藏表单的提交按钮可见,并指示他们在5秒钟以上的时间内按下该按钮。其次,您可以决定将哪些数据传输到第三方服务器。如果仅使用处理表单的方式,则将传递所有发布数据,而这并非总是您想要的。假设307解决方案适用于所有用户,则与307解决方案相同。
希望这会有所帮助!
评论
请将“将点击事件添加到提交按钮”更改为“将提交事件添加到表单”。提交表单的方法不止一种,例如按下Enter键,所有文字输入均会集中显示,更不用说程序化提交了。
–temoto
13年2月4日在10:10
@tghw我知道这已经很老了,但希望您能看到。有没有一种方法可以执行#2(将表单发布到您自己的服务器重定向页面,然后从那里发布到第三方),同时“保证”表单的值没有被修改。仅仅将字段隐藏起来会阻止人们以某种方式停止第二个POST并修改表单的值或完全提交新的POST请求吗?
– DasBeasto
8月9日下午1:28
#2 楼
您可以使用以下方法: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之后,发生事件加载,触发表单提交并将所有数据发布到定义的postbackUrl 。
评论
+1(如果可以的话,我会再加您)。这就是答案。雄辩而直言不讳。您甚至包括了所有代码来执行此操作,而不用费力。我在aspx页面的iframe中使用了它,它完美呈现了所有内容-无需重写url。优秀作品!给使用iframe的用户的提示:我将iframe指向另一个aspx页面,然后执行该代码。
– MikeTeeVee
2012年10月3日在22:54
确实有效!我看到的唯一不好的事情是,如果您按下浏览器的后退按钮,它将再次执行该请求,因此您再也无法真正到达上一页了。为此有工作环境吗?
–施耐德
2013年1月30日12:07
支持这样做的原因是使用307。原因是POST操作旨在成为幂等事务。这个答案仅仅是一个巧合,它可以正常工作,将来很容易被浏览器阻止。
– Sam Rueby
13年4月24日在14:53
@山姆好点。作为反驳:根据最常见的回答,IE开发人员甚至没有读过307。其他阅读它的人错误地实现了它。这意味着307显然会使智能人士困惑(假设浏览器开发人员很聪明),并且容易产生解释错误。至少对于我来说,以上方法很明显,并且它适用于过去和现在的所有浏览器。当我们的开发人员与过去(阅读IE7)和现在/将来进行斗争时,不必太担心未来。恕我直言,既然每个人都正确地得到了,他们应该保持原样。将来阻止它的依据是什么?
–so_mv
2013年12月4日9:00
这与TGHW的第二种选择有何不同?您是否还可能要求别人不小心引入XSS漏洞?
–斯科特
2014年1月3日15:36
#3 楼
在回发时,向您的第三方创建一个HttpWebRequest并发布表单数据,然后完成该操作,您可以在任何需要的地方进行Response.Redirect。
您获得的另一个好处是,不必命名所有服务器控件即可构成第三方表单,可以在构建POST字符串时执行此翻译。
/>
但是,如果您需要用户从此表单中查看响应页面,则唯一的选择是利用Server.Transfer,这可能会或可能不会起作用。
评论
如果我想要一个比asp.net表单更多的表单,这是我将要使用的表单。我需要将一些数据发布到用于3d安全付款的外部网址中,然后才需要从请求中返回信息。这是这样做的方式吗?谢谢
–Barbaros Alp
09年3月25日在17:55
如果您需要用户查看响应,则只需发送回内容和任何适当的标题即可。您可能必须根据相关资源的使用来修改结果的某些方面,但是肯定是可能的。
– Thomas S. Trias
2010年12月1日23:00
用户可能具有无法通过此方法传输的cookie数据,因为这是从服务器发生的。
–斯科特
2014年1月3日15:40
#4 楼
这应该使生活变得更加轻松。您可以在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
#5 楼
ASP.Net 3.5中的新功能是ASP按钮的“ PostBackUrl”属性。您可以将其设置为要直接发布到的页面的地址,然后单击该按钮,而不是像通常那样发布回同一页面,而是将其发布到您指示的页面。便利。确保UseSubmitBehavior也设置为TRUE。#6 楼
认为与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>
#7 楼
可以在asp按钮上设置PostbackUrl以发布到其他页面。如果需要在代码隐藏中进行操作,请尝试Server.Transfer。
#8 楼
@Matt,您仍然可以使用HttpWebRequest,然后将收到的响应定向到实际的输出流响应,这会将响应提供给用户。唯一的问题是所有相对URL都会被破坏。
仍然可以,
#9 楼
这就是我要做的事情:将数据放入标准表单中(没有runat =“ server”属性),并将表单的操作设置为发布到目标异地页面。 br />提交之前,我会使用XmlHttpRequest将数据提交到服务器并分析响应。如果响应表示您应该继续进行异地发布,那么我(JavaScript)将继续该发布,否则我将重定向到我网站上的页面
评论
这可行,但是要注意,您松开了所有ASP.NET服务器端功能。
– senfo
08年12月28日在4:58
#10 楼
在PHP中,您可以使用cURL发送POST数据。是.NET的同类产品吗?
是的,HttpWebRequest,请参阅下面的我的文章。
#11 楼
绝对不要使用GET(和HEAD)方法来做任何有副作用的事情。副作用可能是正在更新Web应用程序的状态,或者可能是在向您的信用卡收费。如果操作有副作用,则应改用其他方法(POST)。如果由于GET产生了一些有害或昂贵的副作用,那将是Web应用程序的错误,而不是用户的错误。根据规范,除非是对GET或HEAD请求的响应,否则用户代理不得自动遵循重定向。当然,很多GET请求的确有一些副作用,即使如果它只是追加到日志文件。重要的是应由应用程序(而不是用户)对这些影响负责。
HTTP规范的相关部分为9.1.1和9.1.2,以及10.3。
评论
这应该是一条评论。
–莱安德罗
12月2日下午2:01
#12 楼
我建议构建一个HttpWebRequest,以编程方式执行您的POST,然后在读取了Response(如果适用)之后重定向。#13 楼
基于Pavlo Neyman方法的可复制粘贴代码目标数据。数据必须可由NewtonSoft Json.NET进行序列化,并且您当然需要引用该库。
只需将其复制粘贴到您的页面中,或者更好但更基础类为页面,并在应用程序中的任何位置使用它。
我的心向所有出于任何原因仍在2019年仍需要使用Web窗体的人致敬。
protected void RedirectPost(string url, IEnumerable<KeyValuePair<string,string>> fields)
{
Response.Clear();
const string template =
@"<html>
<body onload='document.forms[""form""].submit()'>
<form name='form' action='{0}' method='post'>
{1}
</form>
</body>
</html>";
var fieldsSection = string.Join(
Environment.NewLine,
fields.Select(x => $"<input type='hidden' name='{HttpUtility.UrlEncode(x.Key)}' value='{HttpUtility.UrlEncode(x.Value)}'>")
);
var html = string.Format(template, HttpUtility.UrlEncode(url), fieldsSection);
Response.Write(html);
Response.End();
}
private const string JsonDataFieldName = "_jsonData";
protected void RedirectPost<T>(string url, T bodyPayload)
{
var json = JsonConvert.SerializeObject(bodyPayload, Formatting.Indented);
//explicit type declaration to prevent recursion
IEnumerable<KeyValuePair<string, string>> postFields = new List<KeyValuePair<string, string>>()
{new KeyValuePair<string, string>(JsonDataFieldName, json)};
RedirectPost(url, postFields);
}
protected T GetPostData<T>() where T: class
{
var urlEncodedFieldData = Request.Params[JsonDataFieldName];
if (string.IsNullOrEmpty(urlEncodedFieldData))
{
return null;// default(T);
}
var fieldData = HttpUtility.UrlDecode(urlEncodedFieldData);
var result = JsonConvert.DeserializeObject<T>(fieldData);
return result;
}
#14 楼
通常,您只需要在这两个请求之间携带某种状态即可。实际上,有一种非常时髦的方式可以实现,它不依赖JavaScript(请考虑)。Set-Cookie: name=value; Max-Age=120; Path=/redirect.html
有了该cookie,您可以在根据对/redirect.html检索名称=值信息的请求,您可以在此名称/值对字符串中存储任何类型的信息,最多可存储4K数据(典型的cookie限制)。当然,您应该避免这种情况,而应存储状态代码和标志位。
收到此请求后,您将以该状态代码的删除请求作为响应。
Set-Cookie: name=value; Max-Age=0; Path=/redirect.html
我的HTTP有点生锈,我一直通过RFC2109和RFC2965来弄清楚这到底有多可靠,我最好让Cookie来回往返一次,但这似乎不可能,而且,如果您要重定位到另一个域,则第三方cookie对您来说可能是个问题。这仍然可以实现,但不像您在自己的域中进行工作时那样痛苦。属于同一会话(这不太可能,但并非不可能),这可能导致应用程序不一致。
方式是HTTP往返的方式,而没有无意义的URL和JavaScript
我提供此代码作为概念证明:如果此代码在您不熟悉的上下文中运行,我认为您可以弄清楚什么是什么。
这个想法是,当您重定向时,您以某种状态调用Relocate,而您所迁移的URL则调用GetState以获取数据(如果有的话)。
评论
在PHP中,您可以使用cURL发送POST数据。 .NET有可比的功能吗?我认为这是您要找的简单答案。我简直不敢相信它是多么的巧妙... stackoverflow.com/a/6062248/110549
@BrianWarshaw我发现System.Net.Http.HttpClientmsdn.microsoft.com/en-us/library/…非常直观且易于使用。