NSString asscii格式(2进制) 转 utf8格式——解决iOS自己处理http socket数据,遇到Transfer-Encoding: chunked时

时间:2022-05-05 23:56:18

因为需要实现自己的http客户端,就要自己模拟http 的socket通讯;

上行不难,自己处理好http即可。

但下行时,服务器端的动态语言返回数据有可能会是这种格式:

http头
16进制表示的数据长度1
数据1
16进制表示的数据长度2
数据2
……16进制表示的数据长度n
数据n
0

是这种格式时,返回头信息里面会有:

Transfer-Encoding: chunked

这么一个头;数据里面表示每次发送的数据长度的16进制字符并不是html的一部分,需要去掉,如果数据直接使用utf8编码,那么就会出问题:

如果 数据1 里面有中文,则“16进制表示的数据长度1”要比 数据1.length大,因为“16进制表示的数据长度1”是取的2进制长度,但“数据1.length”是以utf8编码来算的


所以不能默认使用utf8编码,得这样:

-(void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    NSString *newMessage = [[NSString alloc] initWithData:data encoding:NSISOLatin1StringEncoding];
    
    NSLog(@"\r\n=================HTTP RESPONSE START=================\r\nData get length: %lu,\r\n%@\r\n=================HTTP RESPONSE END=================\r\n ", (unsigned long)data.length, newMessage);
    [sock readDataWithTimeout:-1 tag:0];
    if(httpStatus<3 && [newMessage rangeOfString:@"Transfer-Encoding: chunked"].length>0){
        isChunked = YES;
        httpStatus = 3 ;
    }
    
    dataGot = [dataGot stringByAppendingString:newMessage];

    httpStatus = 3;
}

最后处理去处长度字符,然后转换为utf8编码:

- (void)socketDidDisconnect:(GCDAsyncSocket *)sock withError:(NSError *)err
{
    NSLog(@"Disconnected %@", err);
    if(httpStatus<3)
        [delegate httpDataGot:@"" rs:NO];
    else{
        if(isChunked){
            NSRange range = [dataGot rangeOfString:@"\r\n\r\n"];
            int len = range.length+range.location;
            dataGot =[dataGot substringFromIndex:len];
            
            NSString* rs = @"";
            NSString* lenStr;
            
            //NSLog(@"data len=%d---\n%@\n", dataGot.length,dataGot);
            
            while(YES){
                range = [dataGot rangeOfString:@"\r\n"];
                if(range.length==0)
                    break;
                lenStr = [dataGot substringToIndex:range.location];
                firstChunkedLen = strtoul([lenStr UTF8String], 0, 16);
                if(firstChunkedLen==0)
                    break;
                dataGot = [dataGot substringFromIndex:range.location+range.length];
                rs = [rs stringByAppendingString:[dataGot substringToIndex:firstChunkedLen]];
                dataGot = [dataGot substringFromIndex:firstChunkedLen];
            }
           /*
             NSString *s1 = [NSString stringWithCString:[rs cStringUsingEncoding:NSISOLatin1StringEncoding] encoding:NSUTF8StringEncoding];
           */
            
            [delegate httpDataGot:[NSString stringWithCString:[rs cStringUsingEncoding:NSISOLatin1StringEncoding] encoding:NSUTF8StringEncoding] rs:YES];
        }
        else
            [delegate httpDataGot:[NSString stringWithCString:[dataGot cStringUsingEncoding:NSISOLatin1StringEncoding] encoding:NSUTF8StringEncoding] rs:YES];
    
    }
    isChunked = NO;
    httpStatus = 0;
}