解析 http-multipart 响应
Posted
技术标签:
【中文标题】解析 http-multipart 响应【英文标题】:Parsing http-multipart response 【发布时间】:2013-09-05 18:00:14 【问题描述】:我需要从 Web 服务接收 http-multipart 响应。包含 JSON 和图像对的多部分响应。
如何分两部分处理响应(JSON 的 NSDictionary 和图像的 NSData)?
提前致谢!
[更新] 我为 NSData 写了一个类别。代码如下:
NSData+MultipartResponses.h
#import <Foundation/Foundation.h>
@interface NSData (MultipartResponses)
- (NSArray *)multipartArray;
- (NSDictionary *)multipartDictionary;
@end
NSData+MultipartResponses.m
#import "NSData+MultipartResponses.h"
@implementation NSData (MultipartResponses)
static NSMutableDictionary *parseHeaders(const char *headers)
NSMutableDictionary *dict=[NSMutableDictionary dictionary];
int max=strlen(headers);
int start=0;
int cursor=0;
while(cursor<max)
while((headers[cursor]!=':')&&(headers[cursor]!='='))
cursor++;
NSString *key=[[NSString alloc] initWithBytes:(headers+start) length:(cursor-start) encoding:NSASCIIStringEncoding];
cursor++;
while(headers[cursor]==' ')
cursor++;
start=cursor;
while(headers[cursor]&&(headers[cursor]!=';')&&((headers[cursor]!=13)||(headers[cursor+1]!=10)))
cursor++;
NSString *value;
if((headers[start]=='"')&&(headers[cursor-1]=='"'))
value=[[NSString alloc] initWithBytes:(headers+start+1) length:(cursor-start-2) encoding:NSASCIIStringEncoding];
else
value=[[NSString alloc] initWithBytes:(headers+start) length:(cursor-start) encoding:NSASCIIStringEncoding];
[dict setObject:value forKey:key];
if(headers[cursor]==';')
cursor++;
else
cursor+=2;
while(headers[cursor]==' ')
cursor++;
start=cursor;
return dict;
- (NSDictionary *)multipartDictionaryWithBoundary:(NSString *)boundary
NSMutableDictionary *dict=[NSMutableDictionary dictionary];
const char *bytes=(const char *)[self bytes];
const char *pattern=[boundary cStringUsingEncoding:NSUTF8StringEncoding];
int cursor=0;
int start=0;
int max=[self length];
int keyNo=0;
while(cursor<max)
if(bytes[cursor]==pattern[0])
int i;
int patternLength=strlen(pattern);
BOOL match=YES;
for(i=0; i<patternLength; i++)
if(bytes[cursor+i]!=pattern[i])
match=NO;
break;
if(match)
if(start!=0)
int startOfHeaders=start+2;
int cursor2=startOfHeaders;
while((bytes[cursor2]!=(char)0x0d)||(bytes[cursor2+1]!=(char)0x0a)||(bytes[cursor2+2]!=(char)0x0d)||(bytes[cursor2+3]!=(char)0x0a))
cursor2++;
if(cursor2+4==max)
break;
if(cursor2+4==max)
break;
else
int lengthOfHeaders=cursor2-startOfHeaders;
char *headers=(char *)malloc((lengthOfHeaders+1)*sizeof(char));
strncpy(headers, bytes+startOfHeaders, lengthOfHeaders);
headers[lengthOfHeaders]=0;
NSMutableDictionary *item=parseHeaders(headers);
int startOfData=cursor2+4;
int lengthOfData=cursor-startOfData-2;
if(([item valueForKey:@"Content-Type"]==nil)&&([item valueForKey:@"filename"]==nil))
NSString *string=[[NSString alloc] initWithBytes:(bytes+startOfData) length:lengthOfData encoding:NSUTF8StringEncoding];
keyNo++;
[dict setObject:string forKey:[NSString stringWithFormat:@"%d", keyNo]];
else
NSData *data=[NSData dataWithBytes:(bytes+startOfData) length:lengthOfData];
[item setObject:data forKey:@"data"];
keyNo++;
[dict setObject:item forKey:[NSString stringWithFormat:@"%d", keyNo]];
cursor=cursor+patternLength-1;
start=cursor+1;
cursor++;
return dict;
- (NSArray *)multipartArray
NSDictionary *dict=[self multipartDictionary];
NSArray *keys=[[dict allKeys] sortedArrayUsingSelector:@selector(localizedStandardCompare:)];
NSMutableArray *array=[NSMutableArray array];
for(NSString *key in keys)
[array addObject:dict[key]];
return array;
- (NSDictionary *)multipartDictionary
const char *bytes=(const char *)[self bytes];
int cursor=0;
int max=[self length];
while(cursor<max)
if(bytes[cursor]==0x0d)
break;
else
cursor++;
char *pattern=(char *)malloc((cursor+1)*sizeof(char));
strncpy(pattern, bytes, cursor);
pattern[cursor]=0x00;
NSString *boundary=[[NSString alloc] initWithCString:pattern encoding:NSUTF8StringEncoding];
free(pattern);
return [self multipartDictionaryWithBoundary:boundary];
@end
【问题讨论】:
可与本主题相关:***.com/questions/22095186/… 【参考方案1】:对我来说,您的代码不起作用。相反,我用纯 Objective-c 重写了该代码: 注意这段代码中的(我的)边界总是有额外的——在下一个边界和最后一个边界之前——那些被剥离了。 返回一个 NSArray,每个部分都有一个 NSDictionary,包含键“headers”作为 NSDictionary,“body”作为 NSData
- (NSArray *)multipartArrayWithBoundary:(NSString *)boundary
NSString *data = [[[NSString alloc] initWithData:self encoding:NSUTF8StringEncoding] autorelease];
NSArray *multiparts = [data componentsSeparatedByString:[@"--" stringByAppendingString:boundary]]; // remove boundaries
multiparts = [multiparts subarrayWithRange:NSMakeRange(1, [multiparts count]-2)]; // continued removing of boundaries
NSMutableArray *toReturn = [NSMutableArray arrayWithCapacity:2];
for(NSString *part in multiparts)
part = [part stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSArray *separated = [part componentsSeparatedByString:@"\n\n"];
NSMutableDictionary *headers = [NSMutableDictionary dictionaryWithCapacity:3];
for(NSString *headerLine in [[separated objectAtIndex:0] componentsSeparatedByString:@"\n"])
NSArray *keyVal = [headerLine componentsSeparatedByString:@":"];
[headers setObject:[[keyVal objectAtIndex:1] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] forKey:[[keyVal objectAtIndex:0] stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
[toReturn addObject:[NSDictionary dictionaryWithObjectsAndKeys:[[separated objectAtIndex:1] dataUsingEncoding:NSUTF8StringEncoding], @"body", headers, @"headers", nil]];
return toReturn;
【讨论】:
以上是关于解析 http-multipart 响应的主要内容,如果未能解决你的问题,请参考以下文章
2018 Multi-University Training Contest 2 部分简单题解析