我们需要进行表单提交并保存一些数据,然后将用户重定向到站点外的页面,但是在重定向过程中,我们需要使用POST而不是GET“提交”表单。

我希望有一个简单的方法来完成这一点,但我开始觉得没有。我想我现在必须创建一个简单的另一个页面,只有我想要的表单,重定向到它,填充表单变量,然后做一个主体。Onload调用脚本,只调用document.forms[0].submit();

谁能告诉我还有别的选择吗?我们可能需要在项目后期进行调整,它可能会变得有点复杂,所以如果有一个简单的方法,我们可以做所有不依赖于其他页面的事情,那就太棒了。

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


当前回答

认为这可能是有趣的分享,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>

其他回答

认为这可能是有趣的分享,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>

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

因此,用户(或他们的浏览器)不应该对GET所做的事情负责。如果由于GET而产生了一些有害或昂贵的副作用,那将是web应用程序的错,而不是用户的错。根据规范,用户代理不能自动跟踪重定向,除非它是对GET或HEAD请求的响应。

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

HTTP规范的相关章节是9.1.1、9.1.2和10.3。

我建议构建一个HttpWebRequest以编程方式执行POST,然后在读取响应后重定向(如果适用)。

HttpWebRequest用于此。

在回发时,创建一个HttpWebRequest到你的第三方并发布表单数据,然后一旦完成,你就可以响应了。转向你想去的地方。

你得到了额外的好处,你不必为所有的服务器控件命名来创建第三方表单,你可以在构建POST字符串时进行这种转换。

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");

但是,如果您需要用户从这个表单中看到响应页面,那么惟一的选择就是使用Server。转移,可能有用,也可能没用。

通常,您所需要的只是在这两个请求之间携带一些状态。实际上有一种非常时髦的方法来做到这一点,它不依赖于JavaScript(想想<noscript/>)。

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

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

在收到此请求后,您将返回响应状态码的删除请求。

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

我的HTTP有点生锈了,我一直在通过RFC2109和RFC2965来弄清楚这有多可靠,最好我想让cookie精确地往返一次,但这似乎不可能,而且,如果你迁移到另一个域,第三方cookie可能对你来说是一个问题。这仍然是可能的,但并不像你在自己的领域内做事情那样轻松。

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

这是<noscript/>的HTTP往返方式,没有无意义的url和JavaScript

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

其思想是在重定向时使用某些状态调用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;
}