【问题标题】:Using a custom NSURLProtocol with UIWebView and POST requests使用带有 UIWebView 和 POST 请求的自定义 NSURLProtocol
【发布时间】:2012-02-15 21:21:51
【问题描述】:

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

myprotocol://myserver/mypath

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

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

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

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

【问题讨论】:

    标签: iphone ios uiwebview nsurlprotocol


    【解决方案1】:

    不尝试使用 POST 请求,一种解决方法是继续对 myprotocol:// URL 使用 GET 请求,但在您的 NSURLProtocol 实现中将它们转换为 http:// POST 请求使用请求查询字符串作为 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/ 的响应一样)。

    【讨论】:

    • 不错的建议。抱歉,我之前没有注意到您的回复。
    【解决方案2】:

    不幸的是,http:https: 方案请求的处理方式与 Foundation Framework 的其他(包括自定义)方案略有不同。显然HTTPBodyHTTPBodyStream 调用相关的NSURLRequest 总是返回nil 以前的。这已经在[NSURLProtocol canInitWithRequest] 的调用之前决定了,因此自定义NSURLProtocol 实现无法影响它(为时已晚)。

    似乎http:https: 使用的NSURLRequest 类与“默认类”不同。此类的默认 GnuStep 实现从 HTTPBodyHTTPBodyStream 调用返回 always nil。因此,特定的实现(例如,PhoneGap 下的一个,可能是 Foundation Framework 的一部分)根据与NSURLProtocol 协商的方案选择NSURLRequest-类型的类。对于自定义方案,您会得到NSURLRequest,它为HTTPBodyHTTPBodyStream 返回nil,这有效地禁止在自定义URI 方案处理程序中使用POST 方法(以及其他带有正文的方法)。

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-01-24
      • 2023-03-22
      • 2011-05-21
      • 1970-01-01
      • 1970-01-01
      • 2014-01-25
      • 1970-01-01
      相关资源
      最近更新 更多