Response.Redirect con POST anziché Get?

Abbiamo l’obbligo di inviare un modulo di invio e salvare alcuni dati, quindi redirect l’utente a una pagina esterna, ma nel reindirizzamento, dobbiamo “inviare” un modulo con POST, non GET.

Speravo che ci fosse un modo semplice per realizzare questo, ma sto iniziando a pensare che non ci sia. Penso che ora devo creare una semplice altra pagina, con solo la forma che voglio, redirect ad essa, compilare le variabili del modulo, quindi fare un body.on caricare la chiamata a uno script che chiama semplicemente document.forms [0] .submit ( );

Qualcuno può dirmi se c’è un’alternativa? Potremmo aver bisogno di modificarlo più avanti nel progetto, e potrebbe essere complicato, quindi se ci fosse un modo facile potremmo fare tutto ciò che non dipende da altre pagine sarebbe fantastico.

Comunque, grazie per tutte le risposte.

    Per fare questo è necessario capire come funzionano i reindirizzamenti HTTP. Quando si utilizza Response.Redirect() , si invia una risposta (al browser che ha effettuato la richiesta) con il codice di stato HTTP 302 , che indica al browser dove andare dopo. Per definizione, il browser lo farà tramite una richiesta GET , anche se la richiesta originale era un POST .

    Un’altra opzione è utilizzare il codice di stato HTTP 307 , che specifica che il browser deve effettuare la richiesta di reindirizzamento allo stesso modo della richiesta originale, ma per richiedere all’utente un avviso di sicurezza. Per farlo, dovresti scrivere qualcosa come questo:

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

    Sfortunatamente, questo non funzionerà sempre. Diversi browser lo implementano in modo diverso , poiché non è un codice di stato comune.

    Purtroppo, a differenza degli sviluppatori di Opera e FireFox, gli sviluppatori di IE non hanno mai letto le specifiche e persino l’IE7 più sicuro e più sicuro reindirizzerà la richiesta POST dal dominio A al dominio B senza alcun avviso o finestra di conferma! Safari agisce anche in modo interessante, mentre non genera una finestra di dialogo di conferma ed esegue il reindirizzamento, butta via i dati POST, modificando efficacemente il reindirizzamento 307 nel 302 più comune.

    Quindi, per quanto ne so, l’unico modo per implementare qualcosa di simile sarebbe usare Javascript. Ci sono due opzioni che posso pensare in cima alla mia testa:

    1. Crea il modulo e il suo attributo action punta al server di terze parti. Quindi, aggiungi un evento click al pulsante di invio che esegue prima una richiesta AJAX sul tuo server con i dati e quindi consente di inviare il modulo al server di terze parti.
    2. Crea il modulo da inviare al tuo server. Quando il modulo viene inviato, mostra all’utente una pagina che contiene un modulo con tutti i dati che vuoi trasmettere, il tutto in input nascosti. Basta mostrare un messaggio come “Reindirizzamento …”. Quindi, aggiungi un evento javascript alla pagina che invia il modulo al server di terze parti.

    Tra i due, sceglierei il secondo, per due motivi. Innanzitutto, è più affidabile del primo perché Javascript non è necessario per il suo funzionamento; per coloro che non lo hanno abilitato, puoi sempre rendere visibile il pulsante di invio per il modulo nascosto e chiedere loro di premerlo se richiede più di 5 secondi. In secondo luogo, è ansible decidere quali dati vengono trasmessi al server di terze parti; se usi semplicemente il modulo nel modo in cui procede, passerai lungo tutti i dati del post, che non è sempre quello che vuoi. Lo stesso vale per la soluzione 307, supponendo che abbia funzionato per tutti i tuoi utenti.

    Spero che questo ti aiuti!

    Puoi usare questo approccio:

     Response.Clear(); StringBuilder sb = new StringBuilder(); sb.Append(""); sb.AppendFormat(@""); sb.AppendFormat("
    ",postbackUrl); sb.AppendFormat("", id); // Other params go here sb.Append("
    "); sb.Append(""); sb.Append(""); Response.Write(sb.ToString()); Response.End();

    Come risultato, subito dopo il client otterrà tutto il codice HTML dal server, si verificherà l’evento onload che triggers il modulo invia e pubblica tutti i dati su definito postbackUrl.

    HttpWebRequest è usato per questo.

    Sul postback, crea una HttpWebRequest a terzi e pubblica i dati del modulo, quindi una volta terminato, puoi Response.Redirect ovunque tu voglia.

    Si ottiene il vantaggio aggiuntivo che non è necessario assegnare un nome a tutti i controlli del server per creare moduli di terze parti, è ansible eseguire questa conversione quando si crea la stringa 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"); 

    Tuttavia, se è necessario che l’utente visualizzi la pagina di risposta da questo modulo, l’unica opzione è utilizzare Server.Transfer, che potrebbe funzionare o meno.

    Questo dovrebbe rendere la vita molto più facile. Puoi semplicemente utilizzare il metodo Response.RedirectWithData (…) nella tua applicazione web facilmente.

     Imports System.Web Imports System.Runtime.CompilerServices Module WebExtensions  _ 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("") sb.AppendFormat("") sb.AppendFormat("
    ", aDestination) For Each key As String In aData sb.AppendFormat("", key, aData(key)) Next sb.Append("
    ") sb.Append("") sb.Append("") aThis.Write(sb.ToString()) aThis.End() End Sub End Module

    Qualcosa di nuovo in ASP.Net 3.5 è questa proprietà “PostBackUrl” dei pulsanti ASP. Puoi impostarlo all’indirizzo della pagina che desideri pubblicare direttamente, e quando viene cliccato quel pulsante, invece di postare di nuovo nella stessa pagina come normale, invece pubblica sulla pagina che hai indicato. Maneggevole. Assicurati che UseSubmitBehavior sia impostato su TRUE.

    Ho pensato che potrebbe essere interessante condividere che heroku fa questo con il suo SSO ai fornitori di componenti aggiuntivi

    Un esempio di come funziona può essere visto nella sorgente allo strumento “kensa”:

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

    E può essere visto in pratica se si gira di javascript. Origine della pagina di esempio:

         Heroku Add-ons SSO   

    PostbackUrl può essere impostato sul tuo pulsante asp per postare in una pagina diversa.

    se hai bisogno di farlo in codebehind, prova Server.Transfer.

    @Opaco,

    È comunque ansible utilizzare HttpWebRequest, quindi indirizzare la risposta ricevuta alla risposta outputstream effettiva, ciò restituirebbe all’utente la risposta. L’unico problema è che qualsiasi url relativo sarebbe rotto.

    Comunque, potrebbe funzionare.

    Ecco cosa farei:

    Inserire i dati in un formato standard (senza attributo runat = “server”) e impostare l’azione del modulo da pubblicare nella pagina esterna del sito di destinazione. Prima dell’invio, invierò i dati al mio server utilizzando XmlHttpRequest e analizzerò la risposta. Se la risposta significa che dovresti andare avanti con il POSTing offsite, allora io (il JavaScript) procederei con il post altrimenti reindirizzerei a una pagina del mio sito

    In PHP, puoi inviare i dati POST con cURL. C’è qualcosa di comparabile per .NET?

    Sì, HttpWebRequest, vedi il mio post qui sotto.

    Suggerisco di creare un HttpWebRequest per eseguire a livello di codice il POST e quindi redirect dopo aver letto la risposta, se applicabile.

    Il metodo GET (e HEAD) non dovrebbe mai essere usato per fare qualsiasi cosa che abbia effetti collaterali. Un effetto collaterale potrebbe essere l’aggiornamento dello stato di un’applicazione web, o potrebbe essere l’addebito sulla tua carta di credito. Se un’azione ha effetti collaterali, dovrebbe essere usato un altro metodo (POST).

    Quindi, un utente (o il suo browser) non dovrebbe essere ritenuto responsabile per qualcosa fatto da un GET. Se alcuni effetti collaterali dannosi o costosi si sono verificati in seguito a un GET, ciò sarebbe dovuto all’applicazione Web e non all’utente. Secondo la specifica, un agente utente non deve seguire automaticamente un reindirizzamento a meno che non si tratti di una risposta a una richiesta GET o HEAD.

    Naturalmente, molte richieste GET hanno alcuni effetti collaterali, anche se si tratta solo di un file di registro. L’importante è che l’applicazione, non l’utente, debba essere ritenuta responsabile di tali effetti.

    Le sezioni pertinenti delle specifiche HTTP sono 9.1.1 e 9.1.2 e 10.3 .

    In genere, tutto ciò di cui hai bisogno è di mantenere uno stato tra queste due richieste. C’è in realtà un modo davvero divertente per fare ciò che non si basa su JavaScript (si pensi ).

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

    Con quel cookie lì, puoi nella seguente richiesta a /redirect.html recuperare le informazioni nome = valore, puoi memorizzare qualsiasi tipo di informazione in questo nome / coppia di valori, fino a dire 4K di dati (limite tipico dei cookie). Ovviamente si dovrebbe evitare questo e memorizzare invece i codici di stato e i bit di segnalazione.

    Dopo aver ricevuto questa richiesta, rispondi in risposta con una richiesta di cancellazione per quel codice di stato.

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

    Il mio HTTP è un po ‘arrugginito Sto passando per RFC2109 e RFC2965 per capire quanto sia affidabile questo, preferibilmente vorrei che il cookie effettuasse il round trip esattamente una volta ma ciò non sembra ansible, anche, i cookie di terze parti potrebbe essere un problema per te se ti stai trasferendo in un altro dominio. Questo è ancora ansible ma non così indolore come quando fai cose nel tuo stesso dominio.

    Il problema qui è la concorrenza, se un utente esperto sta usando più tabs e riesce a intercalare un paio di richieste appartenenti alla stessa sessione (questo è molto improbabile, ma non imansible) questo può portare a incongruenze nell’applicazione.

    È il modo di fare round round HTTP senza URL e JavaScript privi di significato

    Fornisco questo codice come un prof of concept: se questo codice viene eseguito in un contesto che non ti è familiare, penso che tu possa capire quale parte è cosa.

    L’idea è che tu chiami Trasferisci con uno stato quando effettui il reindirizzamento e l’URL che hai trasferito chiama GetState per ottenere i dati (se ce ne sono).

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