我正在尝试通过流媒体上传大文件,最近我收到了这个错误日志:
Error Domain=kCFErrorDomainCFNetwork Code=303 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error 303.)" UserInfo=0x103c0610 {NSErrorFailingURLKey=/adv,/cgi-bin/file_upload-cgic, NSErrorFailingURLStringKey/adv,/cgi-bin/file_upload-cgic}<br>
这是我设置bodystream的地方:
-(void)finishedRequestBody{ // set bodyinput stream
[self appendBodyString:[NSString stringWithFormat:@"\r\n--%@--\r\n",[self getBoundaryStr]]];
[bodyFileOutputStream close];
bodyFileOutputStream = nil;
//calculate content length
NSError *fileReadError = nil;
NSDictionary *fileAttrs = [[NSFileManager defaultManager] attributesOfItemAtPath:pathToBodyFile error:&fileReadError];
NSAssert1((fileAttrs != nil),@"Couldn't read post body file",fileReadError);
NSNumber *contentLength = [fileAttrs objectForKey:NSFileSize];
NSInputStream *bodyStream = [[NSInputStream alloc] initWithFileAtPath:pathToBodyFile];
[request setHTTPBodyStream:bodyStream];
[bodyStream release];
if (staticUpConneciton == nil) {
NSURLResponse *response = nil;
NSError *error = nil;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error];
staticUpConneciton = [[[NSURLConnection alloc]initWithRequest:request delegate:self] retain];
}else{
staticUpConneciton = [[NSURLConnection connectionWithRequest:request delegate:self]retain];
}
}
这就是我写蒸汽的方式:
-(void)stream:(NSStream *)stream handleEvent:(NSStreamEvent)eventCode{
uint8_t buf[1024*100];
NSUInteger len = 0;
switch (eventCode) {
case NSStreamEventOpenCompleted:
NSLog(@"media file opened");
break;
case NSStreamEventHasBytesAvailable:
// NSLog(@"should never happened for output stream");
len = [self.uploadFileInputStream read:buf maxLength:1024];
if (len) {
[self.bodyFileOutputStream write:buf maxLength:len];
}else{
NSLog(@"buf finished wrote %@",self.pathToBodyFile);
[self handleStreamCompletion];
}
break;
case NSStreamEventErrorOccurred:
NSLog(@"stream error");
break;
case NSStreamEventEndEncountered:
NSLog(@"should never for output stream");
break;
default:
break;
}
}
关闭流
-(void)finishMediaInputStream{
[self.uploadFileInputStream close];
[self.uploadFileInputStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
self.uploadFileInputStream = nil;
}
-(void)handleStreamCompletion{
[self finishMediaInputStream];
// finish requestbody
[self finishedRequestBody];
}
我在实现这个方法时发现了这个错误需要NewBodyStream:见下面的代码:
-(NSInputStream *)connection:(NSURLConnection *)connection needNewBodyStream:(NSURLRequest *)request{
[NSThread sleepForTimeInterval:2];
NSInputStream *fileStream = [NSInputStream inputStreamWithFileAtPath:pathToBodyFile];
if (fileStream == nil) {
NSLog(@"NSURLConnection was asked to retransmit a new body stream for a request. returning nil!");
}
return fileStream;
}
这是我设置标题和 mediaInputStream 的地方
-(void)setPostHeaders{
pathToBodyFile = [[NSString alloc] initWithFormat:@"%@%@",NSTemporaryDirectory(),bodyFileName];
bodyFileOutputStream = [[NSOutputStream alloc] initToFileAtPath:pathToBodyFile append:YES];
[bodyFileOutputStream open];
//set bodysteam
[self appendBodyString:[NSString stringWithFormat:@"--%@\r\n", [self getBoundaryStr]]];
[self appendBodyString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n", @"target_path"]];
[self appendBodyString:[NSString stringWithFormat:@"/%@",[NSString stringWithFormat:@"%@/%@/%@",UploaderController.getDestination,APP_UPLOADER,[Functions getDateString]]]];
[self appendBodyString:[NSString stringWithFormat:@"\r\n--%@\r\n", [self getBoundaryStr]]];
[self appendBodyString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"file_path\"; filename=\"%@\"\r\n", fileName]];
[self appendBodyString:[NSString stringWithString:@"Content-Type: application/octet-stream\r\n\r\n"]];
NSString *tempFile = [NSTemporaryDirectory() stringByAppendingPathComponent:@"uploadFile"];
NSError *fileReadError = nil;
NSDictionary *fileAttrs = [[NSFileManager defaultManager] attributesOfItemAtPath:tempFile error:&fileReadError];
NSAssert1((fileAttrs != nil),@"Couldn't read post body file",fileReadError);
NSNumber *contentLength = [fileAttrs objectForKey:NSFileSize];
[request setValue:[contentLength stringValue] forHTTPHeaderField:@"Content-Length"];
NSInputStream *mediaInputStream = [[NSInputStream alloc] initWithFileAtPath:tempFile];
self.uploadFileInputStream = mediaInputStream;
[self.uploadFileInputStream setDelegate:self];
[self.uploadFileInputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.uploadFileInputStream open];
}
这就是我从相机胶卷中复制数据的方式
-(void)copyFileFromCamaroll:(ALAssetRepresentation *)rep{
//copy the file from the camarall to tmp folder (automatically cleaned out every 3 days)
NSUInteger chunkSize = 100 * 1024;
NSString *tempFile = [NSTemporaryDirectory() stringByAppendingPathComponent:@"uploadFile"];
NSLog(@"tmpfile %@",tempFile);
uint8_t *chunkBuffer = malloc(chunkSize * sizeof(uint8_t));
NSUInteger length = [rep size];
NSFileHandle *fileHandle = [[NSFileHandle fileHandleForWritingAtPath: tempFile] retain];
if(fileHandle == nil) {
[[NSFileManager defaultManager] createFileAtPath:tempFile contents:nil attributes:nil];
fileHandle = [[NSFileHandle fileHandleForWritingAtPath:tempFile] retain];
}
NSUInteger offset = 0;
do {
NSUInteger bytesCopied = [rep getBytes:chunkBuffer fromOffset:offset length:chunkSize error:nil];
offset += bytesCopied;
NSData *data = [[NSData alloc] initWithBytes:chunkBuffer length:bytesCopied];
[fileHandle writeData:data];
[data release];
} while (offset < length);
[fileHandle closeFile];
[fileHandle release];
free(chunkBuffer);
chunkBuffer = NULL;
NSError *error;
NSData *fileData = [NSData dataWithContentsOfFile:tempFile options:NSDataReadingMappedIfSafe error:&error];
if (!fileData) {
NSLog(@"Error %@ %@", error, [error description]);
NSLog(@"%@", tempFile);
//do what you need with the error
}
}
任何人,任何想法?我错过了什么?