문제

양식을 제출하고 일부 데이터를 저장한 다음 사용자를 외부 페이지로 리디렉션해야 한다는 요구 사항이 있지만 리디렉션 시 GET이 아닌 POST를 사용하여 양식을 "제출"해야 합니다.

나는 이것을 달성할 수 있는 쉬운 방법이 있기를 바랐지만, 그렇지 않다고 생각하기 시작했습니다.이제 내가 원하는 양식으로 간단한 다른 페이지를 만들고 리디렉션하고 양식 변수를 채운 다음 document.forms[0].submit(만 호출하는 스크립트에 body.onload 호출을 수행해야 한다고 생각합니다. );

대안이 있다면 누구든지 말해 줄 수 있습니까?프로젝트 후반에 이 부분을 조정해야 할 수도 있고 좀 복잡해질 수도 있습니다. 따라서 쉬운 방법이 있다면 다른 페이지에 의존하지 않고 이 모든 작업을 수행할 수 있어 환상적일 것입니다.

어쨌든 모든 답변에 감사드립니다.

도움이 되었습니까?

해결책

이렇게 하려면 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이라도 경고나 확인 대화 상자 없이 도메인 A에서 도메인 B로 POST 요청을 리디렉션합니다!Safari도 흥미로운 방식으로 작동합니다. 확인 대화 상자를 표시하지 않고 리디렉션을 수행하지만 POST 데이터를 버립니다. 307 리디렉션을 더 일반적인 302로 효과적으로 변경합니다.

그래서 제가 아는 한, 이와 같은 것을 구현하는 유일한 방법은 Javascript를 사용하는 것입니다.내 머리 꼭대기에서 생각할 수 있는 두 가지 옵션이 있습니다.

  1. 양식을 작성하고 action 속성은 타사 서버를 가리킵니다.그런 다음 먼저 데이터와 함께 서버에 AJAX 요청을 실행하는 제출 버튼에 클릭 이벤트를 추가한 다음 양식을 타사 서버에 제출할 수 있습니다.
  2. 서버에 게시할 양식을 만듭니다.양식이 제출되면 전달하려는 모든 데이터가 숨겨진 입력으로 포함된 양식이 있는 페이지를 사용자에게 표시합니다."리디렉션 중..."과 같은 메시지를 표시하면 됩니다.그런 다음 타사 서버에 양식을 제출하는 페이지에 자바스크립트 이벤트를 추가합니다.

두 가지 이유 때문에 저는 두 번째를 선택하겠습니다.첫째, 작동하는 데 Javascript가 필요하지 않기 때문에 첫 번째 것보다 더 안정적입니다.활성화하지 않은 사용자의 경우 항상 숨겨진 양식의 제출 버튼을 표시하고 5초 이상 걸리면 누르도록 지시할 수 있습니다.둘째, 타사 서버로 전송되는 데이터를 결정할 수 있습니다.사용하는 경우 양식을 처리하는 대로 모든 게시물 데이터를 전달하게 되지만 항상 원하는 것은 아닙니다.모든 사용자에게 효과가 있다고 가정하면 307 솔루션도 마찬가지입니다.

도움이 되었기를 바랍니다!

다른 팁

다음 접근 방식을 사용할 수 있습니다.

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에 모든 데이터를 게시하는 일이 발생합니다.

이를 위해 HttpWebRequest가 사용됩니다.

포스트백 시 타사에 대한 HttpWebRequest를 생성하고 양식 데이터를 게시한 다음, 완료되면 원하는 곳 어디에서나 Response.Redirect를 수행할 수 있습니다.

타사 양식을 만들기 위해 모든 서버 컨트롤의 이름을 지정할 필요가 없다는 추가 이점을 얻을 수 있습니다. 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.Transfer를 활용하는 것이며 이는 작동할 수도 있고 작동하지 않을 수도 있습니다.

그러면 인생이 훨씬 쉬워질 것입니다.웹 애플리케이션에서 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의 새로운 점은 ASP 버튼의 "PostBackUrl" 속성입니다.직접 게시하고 싶은 페이지의 주소로 설정할 수 있으며 해당 버튼을 클릭하면 평소와 같이 동일한 페이지로 다시 게시되는 대신 지정한 페이지로 게시됩니다.능숙한.UseSubmitBehavior도 TRUE로 설정되어 있는지 확인하세요.

heroku가 추가 기능 공급자에 대한 SSO를 사용하여 이 작업을 수행한다는 사실을 공유하는 것이 흥미로울 것이라고 생각했습니다.

작동 방식의 예는 "kensa" 도구의 소스에서 볼 수 있습니다.

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

그리고 자바스크립트를 켜면 실제로 볼 수 있습니다.예제 페이지 소스:

<!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을 ASP 버튼에 설정하여 다른 페이지에 게시할 수 있습니다.

코드 숨김으로 수행해야 하는 경우 Server.Transfer를 사용해 보세요.

@매트,

여전히 HttpWebRequest를 사용한 다음 수신한 응답을 실제 출력 스트림 응답으로 보낼 수 있습니다. 이렇게 하면 응답이 사용자에게 다시 제공됩니다.유일한 문제는 상대 URL이 손상된다는 것입니다.

그래도 효과가 있을 수 있습니다.

내가 할 일은 다음과 같습니다.

데이터를 표준 형식(runat="server" 속성 없음)에 넣고 대상 오프사이트 페이지에 게시하도록 양식의 작업을 설정합니다.제출하기 전에 데이터를 내 서버에 제출합니다. XmlHttpRequest 사용 그리고 응답을 분석합니다.응답이 오프사이트 게시를 진행해야 한다는 것을 의미하는 경우 나(JavaScript)는 게시물을 계속 진행하고 그렇지 않으면 내 사이트의 페이지로 리디렉션합니다.

PHP에서는 cURL을 사용하여 POST 데이터를 보낼 수 있습니다..NET과 비슷한 것이 있습니까?

예, HttpWebRequest입니다. 아래 내 게시물을 참조하세요.

GET(및 HEAD) 메서드는 부작용이 있는 작업을 수행하는 데 사용되어서는 안 됩니다.부작용으로 인해 웹 애플리케이션의 상태가 업데이트되거나 신용 카드에 요금이 청구될 수 있습니다.작업에 부작용이 있는 경우 대신 다른 방법(POST)을 사용해야 합니다.

따라서 사용자(또는 해당 브라우저)는 GET에 의해 수행된 작업에 대해 책임을 져서는 안 됩니다.GET의 결과로 해롭거나 비용이 많이 드는 부작용이 발생했다면 이는 사용자의 잘못이 아니라 웹 애플리케이션의 잘못일 것입니다.사양에 따르면 사용자 에이전트는 해서는 안 된다 GET 또는 HEAD 요청에 대한 응답이 아닌 한 자동으로 리디렉션을 따릅니다.

물론 로그 파일에 추가하는 경우에도 많은 GET 요청에는 부작용이 있습니다.중요한 것은 사용자가 아닌 애플리케이션이 이러한 결과에 대해 책임을 져야 한다는 것입니다.

HTTP 사양의 관련 섹션은 다음과 같습니다. 9.1.1 및 9.1.2, 그리고 10.3.

프로그래밍 방식으로 POST를 실행하고 해당되는 경우 응답을 읽은 후 리디렉션하도록 HttpWebRequest를 구축하는 것이 좋습니다.

다음을 기반으로 복사하여 붙여넣을 수 있는 코드 Pavlo Neyman의 방법

RedirectPost(string url, T bodyPayload) 및 GetPostData()는 소스 페이지에서 강력한 형식의 데이터를 덤프하고 대상 페이지에서 다시 가져오려는 사람들을 위한 것입니다.데이터는 NewtonSoft Json.NET에서 직렬화할 수 있어야 하며 물론 라이브러리를 참조해야 합니다.

페이지 또는 페이지의 기본 클래스에 복사하여 붙여넣고 애플리케이션의 어느 곳에서나 사용하세요.

어떤 이유로든 2019년에도 여전히 Web Forms를 사용해야 하는 여러분 모두에게 마음이 갑니다.

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

일반적으로 필요한 것은 이 두 요청 사이에 일부 상태를 전달하는 것뿐입니다.실제로 JavaScript에 의존하지 않고 이를 수행하는 정말 펑키한 방법이 있습니다(<noscript/>를 생각해 보세요).

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

해당 쿠키를 사용하면 /redirect.html에 대한 다음 요청에서 이름=값 정보를 검색할 수 있으며, 이 이름/값 쌍 문자열에 최대 4K의 데이터(일반적인 쿠키 제한)까지 모든 종류의 정보를 저장할 수 있습니다.물론 이를 피하고 대신 상태 코드와 플래그 비트를 저장해야 합니다.

이 요청을 받으면 해당 상태 코드에 대한 삭제 요청으로 응답합니다.

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

내 HTTP는 약간 녹슬었습니다. RFC2109 및 RFC2965를 통해 이것이 실제로 얼마나 안정적인지 파악했습니다. 바람직하게는 쿠키가 정확히 한 번만 왕복되기를 원하지만 가능하지 않은 것 같습니다. 다른 도메인으로 이전하는 경우 타사 쿠키가 문제가 될 수 있습니다.이는 여전히 가능하지만 자신의 도메인 내에서 작업을 수행할 때만큼 고통스럽지는 않습니다.

여기서 문제는 동시성입니다. 고급 사용자가 여러 탭을 사용하고 동일한 세션에 속하는 두 개의 요청을 인터리브하는 경우(가능성은 거의 없지만 불가능하지는 않음) 애플리케이션에 불일치가 발생할 수 있습니다.

의미 없는 URL과 JavaScript 없이 HTTP 왕복을 수행하는 <noscript/> 방식입니다.

나는 이 코드를 개념 교수로 제공합니다.익숙하지 않은 상황에서 이 코드를 실행해보면 어떤 부분이 어떤 부분인지 짐작할 수 있을 것 같아요.

아이디어는 리디렉션할 때 일부 상태로 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;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top