使用 NSURLConnection 正确处理重定向 [英] Handling redirects correctly with NSURLConnection

查看:30
本文介绍了使用 NSURLConnection 正确处理重定向的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为此,我将假设原始 url 为 http://host/form,而新 url 为 https://host/form代码>.(请注意,在我发布之前,这两个 URL 都将是安全的.但是,非安全到安全的重定向似乎是一个方便的重定向来测试它.)

For the purposes of this, I'm going to pretend the original url is http://host/form and the new url is https://host/form. (Note that before I ship this, both URLs are going to be secure. However, the nonsecure-to-secure seems like a convenient redirect to test this on.)

我正在使用重定向我的 NSURLConnection 访问 Web API.基本上,我想将我刚刚提交给 http://hostaform 的所有内容重新提交到 https://host/form.我认为这将是默认行为,但看起来正文在重定向中丢失了.

I'm accessing a web API using NSURLConnection that redirects me. Basically, I want to take everything I just submitted to http://hostaform and re-submit it to https://host/form. I thought this would be the default behavior, but it looks like the body is being lost in the redirect.

所以我想我需要处理 NSURLConnection 委托的 connection:willSendRequest:redirectResponse: 事件并重新附加正文.问题是这条消息似乎记录不足.我能找到的关于此方法的唯一信息是 NSURLConnection 类参考,这不是很有帮助.其中包括:

So I think I need to handle the connection:willSendRequest:redirectResponse: event of the NSURLConnection's delegate and re-attach the body. The problem is this message seems woefully underdocumented. The only info I can find on this method is NSURLConnection Class Reference, which isn't very helpful. Among other things, it includes this:

redirectResponse:导致重定向的 URL 响应.如果由于委托参与重定向处理而未发送此方法,则可能为零.
redirectResponse: The URL response that caused the redirect. May be nil in cases where this method is not being sent as a result of involving the delegate in redirect processing.

我不确定这是什么意思.结合初始 willSendRequest: 调用,我认为这意味着即使是在重定向响应之前,我的初始请求也会发送 willSendRequest: .对吗?

I'm not sure what this means. Combined with an initial willSendRequest: invocation, I think this is means willSendRequest: is being sent even for my initial request, prior to the redirect response. Is that correct?

所以我在我的委托中添加了代码以保留正文额外的时间,并添加了这个 willSendRequest: 处理程序:

So I've added code to my delegate to retain the body an extra time, and added this willSendRequest: handler:

- (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 中没有发现任何有用的东西.

It doesn't work. But I'm not even sure if this is the right approach. It seems excessively hackish to me. What should I be doing? Is this documented anywhere? I've found nothing useful in Apple's documentation or using Google so far.

(这是在 iPhone 上,虽然这些类似乎没有太大区别.)

(This is on the iPhone, although there doesn't seem to be much difference in these classes.)

推荐答案

RFC 2616 的第 10.3.2 节 关于此行为:

注意:当自动重定向 POST 请求后接收 301 状态代码,一些现有的 HTTP/1.0 用户代理会错误地将其更改为 GET 请求.

Note: When automatically redirecting a POST request after receiving a 301 status code, some existing HTTP/1.0 user agents will erroneously change it into a GET request.

所以这种行为似乎是非标准的,但却是历史性的.GET 请求不是 POST,它会丢失有效负载.

So this behaviour seems to be non-standard but historical. That GET request is not a POST, and it'll be missing the payload.

有趣的是,这也在同一部分:

Interestingly enough, this is also in the same section:

如果收到 301 状态码以响应其他请求除了 GET 或 HEAD,用户代理不得自动重定向请求,除非它可以被用户确认,因为这可能更改发出请求的条件.

If the 301 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.

这很清楚,似乎表明我们无法解决此问题,但我认为为了我们自己的 Web 服务客户端为我们选择(或控制)的服务而忽略这一点可能是最不坏的选择.

That's pretty clear and seems to indicate we can't fix this, but I think ignoring this for the purpose of our own web service clients for services we pick (or control) is probably the least bad alternative.

那么我们如何解决这个问题?

So how do we solve this?

代替原始问题中的 willSendResponse:,我使用的是:

Instead of the willSendResponse: in the original question, I'm using this:

- (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 发送给我的请求相同的形状,而是创建原始请求的克隆并仅更改 URL 以匹配 Cocoa Touch 发送给我的请求.原始请求仍然是一个带有有效负载的 POST.

The idea here is that instead of cloning the new request and trying to shape it the same as the one Cocoa Touch sends me, I create a clone of the original request and change just the URL to match the request Cocoa Touch sent me. That original request is still a POST with the payload attached.

如果您控制服务器,则值得阅读RFC 2616, section 10.3 以查看是否有更好的代码可供您使用(当然,同时检查 iOS 是否按应有的方式处理了更好的代码).

If you control the server, it's worth reading RFC 2616, section 10.3 in its entirety to see if there's a better code you can use (while checking, of course, that iOS handles the better code as it should).

您还可以制作重定向请求的可变副本,并将其 HTTP 方法替换为原始请求的 HTTP 方法.相同的一般原则,尽管这有利于避免新请求而不是旧请求.在某些情况下可能会更好,但我还没有测试过.

You could also make a mutable copy of the redirected request and replace its HTTP method with the HTTP method of the original request. Same general principle, though that would favour keeping things from the new request rather than the old. In some circumstances that might work better, but I haven't tested this yet.

这篇关于使用 NSURLConnection 正确处理重定向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆