Frage

Wir müssen eine Formularübermittlung vornehmen und einige Daten speichern und den Benutzer dann auf eine Seite außerhalb der Website umleiten, aber bei der Umleitung müssen wir ein Formular mit POST und nicht mit GET „übermitteln“.

Ich hatte gehofft, dass es einen einfachen Weg gäbe, dies zu erreichen, aber ich fange an zu glauben, dass das nicht der Fall ist.Ich denke, ich muss jetzt eine einfache andere Seite erstellen, mit genau dem Formular, das ich möchte, darauf umleiten, die Formularvariablen füllen und dann einen body.onload-Aufruf an ein Skript ausführen, das lediglich document.forms[0].submit( aufruft );

Kann mir jemand sagen, ob es eine Alternative gibt?Möglicherweise müssen wir dies später im Projekt optimieren, und es könnte etwas kompliziert werden. Wenn es also eine einfache Möglichkeit gäbe, könnten wir dies alles unabhängig von einer anderen Seite tun, das wäre fantastisch.

Wie auch immer, vielen Dank für alle Antworten.

War es hilfreich?

Lösung

Dazu müssen Sie verstehen, wie HTTP-Weiterleitungen funktionieren.Wenn Sie verwenden Response.Redirect(), senden Sie eine Antwort (an den Browser, der die Anfrage gestellt hat). HTTP-Statuscode 302, die dem Browser mitteilt, wohin er als nächstes gehen soll.Per Definition erledigt der Browser dies über a GET Anfrage, auch wenn die ursprüngliche Anfrage eine war POST.

Eine andere Möglichkeit ist die Verwendung HTTP-Statuscode 307, die angibt, dass der Browser die Umleitungsanforderung auf die gleiche Weise wie die ursprüngliche Anforderung stellen soll, den Benutzer jedoch mit einer Sicherheitswarnung auffordern soll.Dazu würden Sie etwa Folgendes schreiben:

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

Leider wird das nicht immer funktionieren. Verschiedene Browser implementieren dies unterschiedlich, da es sich nicht um einen allgemeinen Statuscode handelt.

Leider haben die IE-Entwickler im Gegensatz zu den Opera- und Firefox-Entwicklern die Spezifikation nie gelesen, und selbst der neueste und sicherste IE7 leitet die POST-Anfrage ohne Warnungen oder Bestätigungsdialoge von Domäne A zu Domäne B um!Auch Safari verhält sich auf interessante Weise: Während es keinen Bestätigungsdialog auslöst und die Umleitung durchführt, wirft es die POST-Daten weg. Die 307-Weiterleitung wird effektiv in die gebräuchlichere 302-Weiterleitung umgewandelt.

Soweit ich weiß, wäre die einzige Möglichkeit, so etwas zu implementieren, die Verwendung von Javascript.Es gibt zwei Optionen, die mir spontan einfallen:

  1. Erstellen Sie das Formular und haben Sie es action Attributpunkt auf den Drittanbieterserver.Fügen Sie dann der Schaltfläche „Senden“ ein Klickereignis hinzu, das zunächst eine AJAX-Anfrage mit den Daten an Ihren Server ausführt und dann die Übermittlung des Formulars an den Server eines Drittanbieters ermöglicht.
  2. Erstellen Sie das Formular, um es auf Ihrem Server zu veröffentlichen.Wenn das Formular gesendet wird, zeigen Sie dem Benutzer eine Seite mit einem Formular mit allen Daten, die Sie weitergeben möchten, alles in versteckten Eingaben.Zeigen Sie einfach eine Nachricht wie „Weiterleitung …“ an.Fügen Sie dann der Seite ein Javascript-Ereignis hinzu, das das Formular an den Drittanbieterserver sendet.

Von den beiden würde ich mich aus zwei Gründen für die zweite entscheiden.Erstens ist es zuverlässiger als das erste, da für seine Funktion kein Javascript erforderlich ist.Für diejenigen, die es nicht aktiviert haben, können Sie jederzeit die Schaltfläche „Senden“ für das ausgeblendete Formular sichtbar machen und sie anweisen, darauf zu klicken, wenn es länger als 5 Sekunden dauert.Zweitens können Sie entscheiden, welche Daten an den Drittanbieter-Server übertragen werden;Wenn Sie das Formular einfach im Laufe der Zeit verarbeiten, geben Sie alle Beitragsdaten weiter, was nicht immer das ist, was Sie möchten.Das Gleiche gilt für die 307-Lösung, vorausgesetzt, sie funktioniert für alle Ihre Benutzer.

Hoffe das hilft!

Andere Tipps

Sie können diesen Ansatz verwenden:

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

Als Ergebnis erhält der Client direkt nach dem Ereignis den gesamten HTML-Code vom Server laden Es findet ein Vorgang statt, der das Absenden des Formulars auslöst und alle Daten an die definierte postbackUrl sendet.

Hierzu wird HttpWebRequest verwendet.

Erstellen Sie beim Postback eine HttpWebRequest an Ihren Drittanbieter und veröffentlichen Sie die Formulardaten. Sobald dies erledigt ist, können Sie Response.Redirect an eine beliebige Stelle senden.

Sie erhalten den zusätzlichen Vorteil, dass Sie nicht alle Ihre Serversteuerelemente benennen müssen, um das Drittanbieterformular zu erstellen. Sie können diese Übersetzung beim Erstellen der POST-Zeichenfolge vornehmen.

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

Wenn Sie jedoch möchten, dass der Benutzer die Antwortseite dieses Formulars sieht, besteht Ihre einzige Möglichkeit darin, Server.Transfer zu verwenden, und das kann funktionieren oder auch nicht.

Das dürfte das Leben deutlich einfacher machen.Sie können einfach die Methode Response.RedirectWithData(...) in Ihrer Webanwendung verwenden.

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

Etwas Neues in ASP.Net 3.5 ist diese „PostBackUrl“-Eigenschaft von ASP-Buttons.Sie können es auf die Adresse der Seite einstellen, auf der Sie direkt posten möchten. Wenn Sie auf diese Schaltfläche klicken, wird der Beitrag nicht wie üblich auf derselben Seite, sondern auf der von Ihnen angegebenen Seite gepostet.Praktisch.Stellen Sie sicher, dass UseSubmitBehavior ebenfalls auf TRUE gesetzt ist.

Ich dachte, es könnte interessant sein, mitzuteilen, dass Heroku dies mit seinem SSO für Add-on-Anbieter tut

Ein Beispiel dafür, wie es funktioniert, finden Sie in der Quelle des Tools „kensa“:

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

Und das zeigt sich in der Praxis, wenn man Javascript abschaltet.Beispiel einer Seitenquelle:

<!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>

PostbackUrl kann auf Ihrer ASP-Schaltfläche festgelegt werden, um auf einer anderen Seite zu posten.

Wenn Sie es in Codebehind tun müssen, versuchen Sie es mit Server.Transfer.

@Matt,

Sie können weiterhin HttpWebRequest verwenden und dann die Antwort, die Sie erhalten, an die tatsächliche Ausgabestream-Antwort weiterleiten. Dadurch wird die Antwort an den Benutzer zurückgegeben.Das einzige Problem besteht darin, dass alle relativen URLs beschädigt würden.

Dennoch könnte das funktionieren.

Folgendes würde ich tun:

Geben Sie die Daten in ein Standardformular ein (ohne runat="server"-Attribut) und legen Sie die Aktion des Formulars so fest, dass sie auf der externen Zielseite gepostet wird.Vor dem Absenden würde ich die Daten an meinen Server übermitteln mit einem XmlHttpRequest und analysieren Sie die Reaktion.Wenn die Antwort bedeutet, dass Sie mit dem Offsite-POSTing fortfahren sollten, würde ich (das JavaScript) mit dem Beitrag fortfahren, andernfalls würde ich auf eine Seite meiner Website weiterleiten

In PHP können Sie POST-Daten mit cURL senden.Gibt es etwas Vergleichbares für .NET?

Ja, HttpWebRequest, siehe meinen Beitrag unten.

Die GET-Methode (und die HEAD-Methode) sollten niemals dazu verwendet werden, etwas zu tun, das Nebenwirkungen hat.Ein Nebeneffekt könnte darin bestehen, dass der Status einer Webanwendung aktualisiert wird oder Ihre Kreditkarte belastet wird.Wenn eine Aktion Nebenwirkungen hat, sollte stattdessen eine andere Methode (POST) verwendet werden.

Daher sollte ein Benutzer (oder sein Browser) nicht für etwas verantwortlich gemacht werden, das ein GET ausführt.Wenn infolge eines GET ein schädlicher oder kostspieliger Nebeneffekt auftritt, ist dies die Schuld der Webanwendung und nicht des Benutzers.Laut Spezifikation ein Benutzeragent darf nicht Folgen Sie automatisch einer Weiterleitung, es sei denn, es handelt sich um eine Antwort auf eine GET- oder HEAD-Anfrage.

Natürlich haben viele GET-Anfragen einige Nebenwirkungen, selbst wenn sie nur an eine Protokolldatei angehängt werden.Wichtig ist, dass die Anwendung und nicht der Benutzer für diese Auswirkungen verantwortlich gemacht werden sollte.

Die relevanten Abschnitte der HTTP-Spezifikation sind 9.1.1 und 9.1.2, Und 10.3.

Ich schlage vor, eine HttpWebRequest zu erstellen, um Ihren POST programmgesteuert auszuführen und dann ggf. nach dem Lesen der Antwort umzuleiten.

Kopier- und einfügbarer Code basierend auf Pavlo Neymans Methode

RedirectPost(string url, T bodyPayload) und GetPostData() sind für diejenigen gedacht, die nur einige stark typisierte Daten auf der Quellseite ausgeben und sie auf der Zielseite zurückholen möchten.Die Daten müssen von NewtonSoft Json.NET serialisierbar sein und Sie müssen natürlich auf die Bibliothek verweisen.

Kopieren Sie es einfach, fügen Sie es in Ihre Seite(n) oder besser noch in die Basisklasse für Ihre Seiten ein und verwenden Sie es an einer beliebigen Stelle in Ihrer Anwendung.

Mein Mitgefühl gilt allen, die im Jahr 2019, aus welchen Gründen auch immer, noch auf Web Forms zurückgreifen müssen.

        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;
        }

Normalerweise müssen Sie lediglich einen Status zwischen diesen beiden Anforderungen übertragen.Es gibt tatsächlich eine wirklich coole Möglichkeit, dies zu tun, die nicht auf JavaScript basiert (denken Sie an <noscript/>).

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

Mit diesem Cookie können Sie in der folgenden Anfrage an /redirect.html die Name=Wert-Informationen abrufen. Sie können jede Art von Informationen in dieser Name/Wert-Paarzeichenfolge speichern, bis zu 4 KB Daten (typisches Cookie-Limit).Natürlich sollten Sie dies vermeiden und stattdessen Statuscodes und Flagbits speichern.

Nach Erhalt dieser Anfrage antworten Sie im Gegenzug mit einer Löschanfrage für diesen Statuscode.

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

Mein HTTP ist etwas eingerostet. Ich habe RFC2109 und RFC2965 durchgesehen, um herauszufinden, wie zuverlässig das wirklich ist. Am liebsten würde ich das Cookie genau einmal umrunden lassen, aber das scheint auch nicht möglich zu sein. Cookies von Drittanbietern können für Sie ein Problem darstellen, wenn Sie zu einer anderen Domain wechseln.Dies ist immer noch möglich, aber nicht so schmerzlos, wie wenn Sie Dinge in Ihrer eigenen Domäne erledigen.

Das Problem hierbei ist die Parallelität. Wenn ein Hauptbenutzer mehrere Registerkarten verwendet und es schafft, mehrere Anforderungen derselben Sitzung zu verschachteln (dies ist sehr unwahrscheinlich, aber nicht unmöglich), kann dies zu Inkonsistenzen in Ihrer Anwendung führen.

Es ist die <noscript/>-Methode, um HTTP-Roundtrips ohne bedeutungslose URLs und JavaScript durchzuführen

Ich stelle diesen Code als Profi zur Verfügung:Wenn dieser Code in einem Kontext ausgeführt wird, mit dem Sie nicht vertraut sind, können Sie meiner Meinung nach herausfinden, welcher Teil welcher ist.

Die Idee besteht darin, dass Sie Relocate mit einem bestimmten Status aufrufen, wenn Sie umleiten, und die URL, die Sie verschoben haben, GetState aufruft, um die Daten (falls vorhanden) abzurufen.

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;
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top