Afnetworking: Swift GB2312

Created on 8 Sep 2016  ·  12Comments  ·  Source: AFNetworking/AFNetworking

pod 'AFNetworking', '~> 3.0.4'

Sever response:
{ status code: 200, headers {
"Cache-Control" = private;
"Content-Length" = 164;
"Content-Type" = "text/html; charset=gb2312";
Date = "";
Server = "Microsoft-IIS/7.5";
"X-AspNet-Version" = "4.0.30319";
"X-AspNetMvc-Version" = "4.0";
"X-Powered-By" = "ASP.NET";
} }

So I set the AFHTTPSessionManager property like this:
let enc = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(cfEnc.rawValue))
manager.responseSerializer.stringEncoding = enc

This code :
NSStringEncoding stringEncoding = self.stringEncoding; if (response.textEncodingName) { CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName); if (encoding != kCFStringEncodingInvalidId) { stringEncoding = CFStringConvertEncodingToNSStringEncoding(encoding); } }
change the stringEncoding value 2147485234 to 2147486000. And then decodeing failure.
2355aa4e-354d-4d6e-9b42-2ac1b28edc33

Most helpful comment

In order to avoid modifying AFNetworking, you should use your own response serializer. Here’s one that should work for your case of GB2312-encoded json served as text/html:

@interface LenientGB2312JSONResponseSerializer : AFJSONResponseSerializer
@end

@implementation LenientGB2312JSONResponseSerializer

- (NSSet <NSString *> *) acceptableContentTypes
{
    return [[super acceptableContentTypes] setByAddingObject:@"text/html"];
}

- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
                                    data:(nullable NSData *)data
                                   error:(NSError * _Nullable __autoreleasing *)error
{
    NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingEUC_CN);
    NSString *string = [[NSString alloc] initWithData:data encoding:encoding];
    return [super responseObjectForResponse:response data:[string dataUsingEncoding:NSUTF8StringEncoding] error:error];
}

@end

Then simply use this custom response serializer instead of the default one:

manager.responseSerializer = [LenientGB2312JSONResponseSerializer new];

All 12 comments

pod 'AFNetworking', '~> 3.1.0'

2b836027-6e69-4d05-b917-aceb30cb0993

The data can't be decodeing which is encodeing by GB2312. The property stringEncoding of AFHTTPResponseSerializer is not used.

[NSJSONSerialization:JSONObjectWithData] seems to assume the data passed in uses UTF8 encoding. This may be a potential issue for those response with other encoding such as GB2312. I'll take a look at it.

I did a little research. 00e7a8bcd84d96d3ec31188fa73551b4d0c6da93 removed a workaround with Unicode character escape by completely removeing the NSData -> NSString -> NSData process. However, this also negelect the situation where response.textEncodingName is not UTF-8.

@0xced Am I missing any information on this?

Yes, thank you very much!
I had modified the code like this (version 3.0.4)
image
Do you have a better solution?

This is not a very good solution (you should not be modifying AFNetworking code) but I need to know more to give you a good answer. Are you trying to parse an html result or a JSON result?

The content type says text/html; charset=gb2312 but it looks like you are parsing it as JSON. Is the URL you are accessing public so that we can have a look?

Sorry, this URL is private. The response is a JSON string encoding by GB2312. But AFNetworking code is not support decoding by GB2312.

In version 3.0.4
NSStringEncoding stringEncoding = self.stringEncoding;
if (response.textEncodingName) {
CFString Encoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);
if (encoding != kCFStringEncodingInvalidId) {
stringEncoding = CFStringConvertEncodingToNSStringEncoding(encoding);
}
}
This code change the stringEncoding value 2147485234 to 2147486000. And then decoding failure. '2147485234' is the right value.

And in version 3.1.0
There is no 'stringEncoding' property to decoding.

When the string contain traditional Chinese the responseObject will be nil. Such as '繁體字'. If all of its characters is simplified Chinese , it works.

@0xced @skyline75489 Thanks you very much to help me!

Honestly, the response vlolates almost all the spec it can possibly violate. JSON response should be encoded in UTF-8 and has application/json content type. You'd better contact the server side to fix this to prevent further issue.

@skyline75489 ahahaha. The server side will never never fix this. I had contacted many times. It's not a good idea. And modifying AFNetworking code is the only way now. Thank you for your help!

@myafer Fair enough. I think this issue can be closed now. Some clarification will be added to the documentation for this.

@skyline75489 OK, thanks!

In order to avoid modifying AFNetworking, you should use your own response serializer. Here’s one that should work for your case of GB2312-encoded json served as text/html:

@interface LenientGB2312JSONResponseSerializer : AFJSONResponseSerializer
@end

@implementation LenientGB2312JSONResponseSerializer

- (NSSet <NSString *> *) acceptableContentTypes
{
    return [[super acceptableContentTypes] setByAddingObject:@"text/html"];
}

- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
                                    data:(nullable NSData *)data
                                   error:(NSError * _Nullable __autoreleasing *)error
{
    NSStringEncoding encoding = CFStringConvertEncodingToNSStringEncoding(kCFStringEncodingEUC_CN);
    NSString *string = [[NSString alloc] initWithData:data encoding:encoding];
    return [super responseObjectForResponse:response data:[string dataUsingEncoding:NSUTF8StringEncoding] error:error];
}

@end

Then simply use this custom response serializer instead of the default one:

manager.responseSerializer = [LenientGB2312JSONResponseSerializer new];

@0xced OK! Thank you!

Was this page helpful?
0 / 5 - 0 ratings