25

この目的のために、元のURLがhttp://host/formであり、新しいURLがであると偽りhttps://host/formます。(これを出荷する前に、両方のURLが安全になることに注意してください。ただし、非安全から安全へのリダイレクトは、これをテストするための便利なリダイレクトのようです。)

NSURLConnectionリダイレクトを使用してWebAPIにアクセスしています。http://hostaform基本的には、送信したばかりのすべてを取得して、に再送信したいと思いhttps://host/formます。これがデフォルトの動作になると思いましたが、リダイレクトで本文が失われているようです。

connection:willSendRequest:redirectResponse:ですから、デリゲートのイベントを処理してNSURLConnection、ボディを取り付け直す必要があると思います。問題は、このメッセージがひどく文書化されていないように見えることです。このメソッドで私が見つけることができる唯一の情報はNSURLConnectionクラスリファレンスですが、これはあまり役に立ちません。特に、これが含まれます:

redirectResponse:リダイレクトの原因となったURL応答。リダイレクト処理にデリゲートが関与した結果、このメソッドが送信されない場合は、nilになる可能性があります。

これが何を意味するのかわかりません。最初の呼び出しと組み合わせると、これは、リダイレクト応答の前に、最初の要求に対しても送信されていることwillSendRequest:を意味すると思います。willSendRequest:あれは正しいですか?

そこで、本文を余分に保持するコードをデリゲートに追加し、次のwillSendRequest:ハンドラーを追加しました。

- (NSURLRequest *)connection: (NSURLConnection *)inConnection
             willSendRequest: (NSURLRequest *)inRequest
            redirectResponse: (NSURLResponse *)inRedirectResponse;
{
    if (inRedirectResponse) {
        NSMutableURLRequest *r = [[inRequest mutableCopy] autorelease];
        [r setURL: [inRedirectResponse URL]];
        [r setHTTPBody: body];
        return r;
    } else {
        return inRequest;
    }
}

動作しません。しかし、これが正しいアプローチであるかどうかさえわかりません。それは私には過度にハックのようです。私は何をすべきですか?これはどこかに文書化されていますか?これまでのところ、AppleのドキュメントやGoogleの使用に役立つものは何も見つかりませんでした。

(これはiPhoneにありますが、これらのクラスには大きな違いはないようです。)

4

4 に答える 4

38

この動作については、 RFC2616のセクション10.3.2に注記があります。

注:301ステータスコードを受信した後にPOSTリクエストを自動的にリダイレクトする場合、一部の既存のHTTP/1.0ユーザーエージェントは誤ってそれをGETリクエストに変更します。

したがって、この動作は非標準的ですが、歴史的なもののようです。そのGETリクエストはではなくPOST、ペイロードが欠落しています。

興味深いことに、これも同じセクションにあります。

GETまたはHEAD以外の要求に応答して301ステータスコードを受信した場合、ユーザーが確認できない限り、ユーザーエージェントは要求を自動的にリダイレクトしてはなりません。これにより、要求が発行された条件が変わる可能性があります。

これは非常に明確であり、これを修正できないことを示しているようですが、私たちが選択(または制御)するサービスの独自のWebサービスクライアントの目的でこれを無視することは、おそらく最も悪い選択肢ではないと思います。

では、これをどのように解決しますか?

元の質問の代わりにwillSendResponse:、私はこれを使用しています:

- (NSURLRequest *)connection: (NSURLConnection *)connection
             willSendRequest: (NSURLRequest *)request
            redirectResponse: (NSURLResponse *)redirectResponse;
{
    if (redirectResponse) {
        // we don't use the new request built for us, except for the URL
        NSURL *newURL = [request URL];
        // Previously, store the original request in _originalRequest.
        // We rely on that here!
        NSMutableURLRequest *newRequest = [_originalRequest mutableCopy];
        [newRequest setURL: newURL];
        return newRequest;
    } else {
        return request;
    }
}

ここでの考え方は、新しいリクエストのクローンを作成して、Cocoa Touchから送信されたものと同じように形作るのではなく、元のリクエストのクローンを作成し、CocoaTouchから送信されたリクエストに一致するようにURLだけを変更するというものです。その元のリクエストはPOST、ペイロードが添付されたままです。

サーバーを制御する場合は、RFC 2616のセクション10.3全体を読んで、使用できるより良いコードがあるかどうかを確認する価値があります(もちろん、iOSがより良いコードを適切に処理することを確認します)。

リダイレクトされたリクエストの可変コピーを作成し、そのHTTPメソッドを元のリクエストのHTTPメソッドに置き換えることもできます。同じ一般原則ですが、それは古いものよりも新しい要求から物事を遠ざけることを支持するでしょう。状況によってはうまくいくかもしれませんが、私はまだこれをテストしていません。

于 2009-09-18T20:13:23.380 に答える
13

サーバーから送信されたHTTP応答ステータスコードをチェックして、GETを送信するかPOSTを繰り返すかを判断する必要があります。303(または302)の場合は、GETリクエストを送信します。307については、POSTを繰り返します。

于 2010-08-03T04:01:52.677 に答える
4

リダイレクトに関しても同じ問題がありました。AJSoaksに感謝します!彼の提案通りに試してみたところ、問題は解決しました。

そのため、POSTメソッドを使用してユーザー名とパスワードを投稿しようとしましたが、サーバーがリクエストをリダイレクトしているのがわかりました。AJSoaksが言うように、302エラーが発生した場合は、リクエストを繰り返す必要がありますが、今回は前のPOSTの代わりにGETメソッドを使用します。

...ある時点で、次の行があります。... IBAction(ボタンが押された)メソッドの場合、または任意の場所にある可能性があります...

NSMutableString *postString = [[NSMutableString alloc] init];

[postString appendString:@"username=YourUsername&password=YourPassword"];

    //the original URL (https means that it supports SSL protocol)
    //it doesn't change anything, don't worry about it
NSURL *URL = [NSURL URLWithString:@"https://loginWebpageURL"];

NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:URL];

[request setHTTPMethod:@"POST"];    
[request setValue:[NSString stringWithFormat:@"%d", [postString length]] forHTTPHeaderField:@"Content-length"];
[request setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-type"];
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];

[NSURLConnection connectionWithRequest:request delegate:self];

[postString release];
[request release];

次の署名を使用して、リダイレクトNSURLConnectionデリゲートメソッドも実装する必要があります。

- (NSURLRequest *)connection:(NSURLConnection *)connection
            willSendRequest:(NSURLRequest *)request
           redirectResponse:(NSURLResponse *)redirectResponse

このメソッド内で、SERVERのエラー302または303が発生した場合は、次のコードのようなものを実装する必要があります。表示されたコードをコピーして、新しいURL(リダイレクト)に置き換えてください。ブラウザに表示される新しいURL、または必要に応じて、将来的にはFirebug(Firefoxプラグイン)またはSafariWEBINSPECTORで確認することもできます。Firebugを使用する場合、「ネット」オプションの下にあるすべての情報を見つけることができます。

if (redirectResponse) {

    NSLog(@"REDIRECT");
    NSMutableURLRequest *requestTmp = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"https://areaclienti.tre.it/selfcare/areaclienti133/4552_infoCosti_ITA_HTML.xsl"]];

    return [requestTmp autorelease];
}

//return original request in case thay there is no redirecting...
else return request;
于 2011-03-06T16:16:04.210 に答える
0

NSURLConnectionは、「willSendRequest:(NSURLRequest *)inRequest」のリダイレクトされた要求にoriginalRequestヘッダーを追加しません。

この問題を回避するには、リダイレクトされたリクエストに「originalRequest.headers」を追加します。

于 2014-04-01T00:21:07.120 に答える