9

在我的 iOS 应用程序中,我使用 UIWebView 和自定义协议(使用我自己的 NSURLProtocol 实现)。我一直非常小心地确保每当我加载一个 url 时,我都会将类似这样的内容加载到我的 UIWebView 中:

我的协议://我的服务器/我的路径

在我的 NSURLProtocol 实现中,我获取了 NSURLRequest 的可变副本,将 URL 转换为 http: 并将其发送到我的服务器。

一切都适用于 HTTP GET 请求。我遇到的问题是 POST 请求。如果请求使用我的自定义协议,UIWebView 似乎没有正确编码 HTTPBody 中的表单数据。

一种解决方法是,因为我对服务器请求使用 HTTPS,所以我注册协议处理程序以拦截 http: 而不是 myprotocol: 并且我可以将所有调用转换为 https: This other question, here指出了我解决方案:

但我想知道是否有任何替代和/或更好的方法来完成我想要的。

4

2 回答 2

6

替代尝试使用 POST 请求,一种解决方法是继续对myprotocol://URL 使用 GET 请求,但在您的NSURLProtocol实现中将它们转换为使用请求查询字符串作为 POST 正文的对您的服务器http:// POST 请求。

使用 GET 请求发送大量数据的担忧在于,在请求链的某个地方,请求行可能会被截断。但是,对于本地实现的协议,这似乎不是问题。

我编写了一个简短的 Cordova 测试应用程序进行实验,我发现我能够毫无问题地发送超过 1 MiB 的数据到 HTTP 请求回显服务http://http-echo.jgate.de/

这是我的startLoading实现:

- (void)startLoading {
    NSURL *url = [[self request] URL];
    NSString *query = [url query];
    // Create a copy of `url` without the query string.
    url = [[[NSURL alloc] initWithScheme:@"http" host:@"http-echo.jgate.de" path:[url path]] autorelease];
    NSMutableURLRequest *newRequest = [NSMutableURLRequest requestWithURL:url];
    [newRequest setHTTPMethod:@"POST"];
    [newRequest setAllHTTPHeaderFields:[[self request] allHTTPHeaderFields]];
    [newRequest addValue:@"close" forHTTPHeaderField:@"Connection"];
    [newRequest addValue:@"application/x-www-form-urlencoded;charset=UTF-8" forHTTPHeaderField:@"Content-Type"];
    [newRequest setHTTPBody:[query dataUsingEncoding:NSUTF8StringEncoding]];
    urlConnection = [[NSURLConnection alloc] initWithRequest:newRequest delegate:self];
    if (urlConnection) {
        receivedData = [[NSMutableData data] retain];
    }
}

然后我实现了NSURLConnection协议方法以转发到适当的NSURLProtocolClient方法,但在以下情况下建立响应数据Transfer-Encoding:chunked(如来自http://http-echo.jgate.de/的响应的情况)。

于 2012-06-30T13:53:59.593 回答
4

不幸的是,它看起来像这样,http:并且https:方案请求的处理方式与 Foundation Framework 的其他(包括自定义)方案略有不同。显然HTTPBody,并且总是要求以前的HTTPBodyStream相关NSURLRequest回报。nil这是已经决定的,[NSURLProtocol canInitWithRequest]因此自定义NSURLProtocol实现无法影响它(为时已晚)。

似乎使用不同NSURLRequest的类http:https:不是“默认类”。此类的默认 GnuStep 实现总是 nilHTTPBodyHTTPBodyStream调用返回。因此,特定的实现(例如,PhoneGap 下的一个,可能是 Foundation Framework 的一部分)NSURLRequest根据事先咨询的方案选择 -type 类NSURLProtocol。对于自定义方案,您将获得两者NSURLRequest的返回值,这有效地禁止在自定义 URI 方案处理程序中使用 POST 方法(以及其他带有正文的方法)。nilHTTPBodyHTTPBodyStream

也许有一种方法可以影响NSURLRequest实际使用哪个类的决定,但我目前还不知道。

作为一种解决方法,您仍然可以使用http:https:计划并[NSURLProtocol canInitWithRequest]根据其他标准(例如主机名)进行决定。

于 2014-01-01T14:21:47.983 回答