我的应用程序通过HTTP传输数据。 有效,我这样做:
- 初始化并开始连接:
NSURLSessionConfiguration* defaultConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession* session = [NSURLSession sessionWithConfiguration:defaultConfiguration delegate:self delegateQueue:nil];
NSInputStream* inputStream = [NSInputStream inputStreamWithData:/*data*/];
NSURL* url = /*init from string*/
NSMutableRequest* request : [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBodyStream = inputStream;
[request addValue:@"no-cache" forHTTPHeaderField:@"Cache-Control"];
[request addValue:@"9999999" forHTTPHeaderField:@"Content-Length"]; // Weird isn't it? But this is in server's specs for live streaming.
NSURLSessionUploadTask* uploadTask = [session uploadTaskWithStreamedRequest:request];
[uploadTask resume];
- NSURLSessionTaskDelegate
实施的一部分:
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
needNewBodyStream:(void (^)(NSInputStream * bodyStream))completionHandler
{
NSInputStream* inputStream = nil;
NSOutputStream* outputStream = nil;
// Bind inputStream and outputStream
self.inputStream = inputStream;
self.outputStream = outputStream;
[self.outputStream setDelegate:/*NSStreamDelegate implementation*/];
[self.outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.outputStream open];
completionHandler(self.inputStream);
}
- NSStreamDelegate
实施的一部分:
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
switch (eventCode) {
case NSStreamEventOpenCompleted:
// to handle...
break;
case NSStreamEventHasSpaceAvailable:
// Producer/Consumer's consumer here, and when data is available:
[self.outputStream write:/*data*/ maxLength:/*data length*/];
break;
case NSStreamEventErrorOccurred:
// to handle...
break;
case NSStreamEventEndEncountered:
// to handle...
break;
default:
break;
}
}
准确地说,我的代码中没有显示的内容:我的连接需要摘要式身份验证。我用来构建请求的URL既不包含登录信息也不包含密码信息。在我发送第一个数据包之后,服务器发送给我401,因此我的应用程序以didReceiveChallenge:
方法执行身份验证并使用auth发送请求(此处为Digest)并且数据正在连续发送。一切都像魅力!
现在,我的问题。较新的服务器版本仅在整个请求结束时响应。所以当我发送我的请求和我的数据体(连续发送)服务器忽略数据时,最后给我发送一个401:我无法执行Digest身份验证。我的解决方案是添加标题“Expect:100-continue”......它的工作原理(部分地,继续阅读;))服务器响应我:D ...但是没有数据体传输并且连接已关闭juste在我的应用程序使用Digest auth信息发回请求之后。试想一下,我在示例代码中添加了[request addValue:@"100-continue" forHTTPHeaderField:@"Expect"];
。 needNewBodyStream:
根本没有电话。
摘要(Wireshark跟踪):
使用我的应用:
使用curl和相同的标题:
修改
我的应用程序使用Digest auth发送请求后,服务器没有响应。我认为这是问题,这就是我的连接关闭的原因。但是curl无论如何都要发送数据,我也想做同样的事情。有什么想法吗?
EDIT2:
我应该实现自己的NSURLProtocol
并在身份验证后删除Expect: 100-continue
标头,以使我的应用能够发送数据正文吗?更好:有没有办法覆盖默认的NSURLProtocol
HTTP规范,而不是从头开始重写?
替代方法(重要):
我让我的应用程序像黑客一样工作。首先,我发送一个HTTP(POST)请求,既没有数据也没有凭据来强制didReceiveChallenge:
被调用。在此回调中,我使用NSURLCredentialPersistenceForSession
参数计算身份验证,以便在会话的所有生命周期中将此信息与会话绑定。然后我取消这个请求并创建一个新的负责流数据(就像我的示例代码一样,在这篇帖子的顶部):Digest auth自动包含在发送的第一个数据包中。
这是一个解决方案,使其在这种情况下起作用并帮助人们。但这不是我想要的解决方案,所以我让这个问题得不到解决,并希望找到一个使用Expect: 100-continue
和单个请求的解决方案。谢谢!