简体   繁体   English

AFNetworking从错误的端点获取响应JSON

[英]AFNetworking getting response JSON from the wrong endpoint

I am seeing a really weird and random issue in my code that I can't track down. 我在代码中看到了一个非常奇怪的随机问题,无法追踪。 I am getting crashes in my data model init methods when returning from AFNetworking JSON request methods. 从AFNetworking JSON请求方法返回时,我的数据模型init方法崩溃。 When the app does crash I am able to step back in the call stack to debug the what the JSON request/response was. 当应用程序崩溃时,我可以返回调用堆栈以调试JSON请求/响应的内容。 The weird part is when I check the URL, request, and resonseJSON. 奇怪的是,当我检查URL,请求和resonseJSON时。 The responseJSON does not match the expected result of the URL/request. responseJSON与URL /请求的预期结果不匹配。 It's like I am getting some other API methods call and data. 就像我正在获取其他一些API方法调用和数据一样。 Because the data/JSON is not what I expect the app will crash on model init. 因为数据/ JSON不是我期望的,所以应用程序将在模型初始化时崩溃。

The data I get back is usually different and not always the same. 我获取的数据通常是不同的,并不总是相同的。 Sometimes the data is from endpoint A and sometimes it is from B, it's never consistent. 有时数据是来自端点A的,有时是来自B的,这永远是不一致的。 It does however seem to crash consistently in the same model object. 但是,它似乎在同一模型对象中始终崩溃。

Request endpoint A data but I get back endpoint B data. 请求端点A数据,但我取回端点B数据。 When I debug the AFHttpOperation when it crashes I see this is the result. 当我崩溃时调试AFHttpOperation时,我看到的是结果。 It's almost like 2 calls are getting crossed and is some type of race condition. 几乎就像有2个电话被越过一样,这是某种竞争状况。 Below is a sample of my model object, Rest client, and model access layer. 以下是我的模型对象,Rest客户端和模型访问层的示例。

Model Object 模型对象

@implementation Applications

- (id)initWithData:(NSDictionary *)appData forLocation:(Location *)location inCategory:(Category *)category {
    // appData is the JSON returned by The Rest Client and AFNetworking
    self = [super init];
    DDLogVerbose(@"appData = %@", appData);
    if (self) {
        _location = location;
        _listeners = [NSMutableArray mutableArrayUsingWeakReferences];
        _devices = [[NSMutableDictionary alloc] init];
        _category = category;
        _subscriptions = [Utility sanitizeArray:appData[@"Subscriptions"]];
    }
    return self;
}

@end

@implementation Location

- (void)refreshApplications {
    [[Model shared] appsForLocation:self 
                            success:^(NSObject *obj) {
        self.apps = nil; //we have to get our apps again
        self.apps = [NSMutableArray array];

        NSArray *newApps = (NSArray *) obj;
        for (NSDictionary *app in newApps) {
            **// This is where it's crashing!**
            Applications *newApp = [[Applications alloc] initWithData:app
                                                          forLocation:self
                                                           inCategory:[[SmartAppCategory alloc] init]];
            [self.apps addObject:newApp];
        }

        [self notifyListeners];
    }
                            error:nil];
}

@end

Rest Client 休息客户

@interface Rest

+ (Rest *)sharedClient;
- (void)GET:(NSString *)path parameters:(NSDictionary *)params success:(SuccessCallback)sCallback error:(ErrorCallback)eCallback;

@end

@implementation Rest

+ (Rest *)sharedClient {
    static dispatch_once_t token;
    static Rest *shared = nil;
    dispatch_once(&token, ^{
        shared = [[Rest alloc] init];
    });
    return shared;
}

- (id)init {
    self = [super init];
    if (self) {
        [self createClients];
    }
    return self;
}

- (void)createClients {
    // Setup the Secure Client
    // Private implementation properties
    self.secureClient = [[AFOAuth2Client alloc] initWithBaseURL:baseUrl clientID:OAUTH2_CLIENT_ID secret:OAUTH2_CLIENT_SECRET];
    [self.secureClient setParameterEncoding:AFJSONParameterEncoding];
    AFOAuthCredential *credential = (AFOAuthCredential *) [NSKeyedUnarchiver unarchiveObjectWithData:[KeyChainStore dataForKey:KEYCHAIN_SETTINGS_AFOAuthCredential]];
    if (credential) {
        [self.secureClient setAuthorizationHeaderWithToken:credential.accessToken];
    }

    // Setup the Anonymous Client
    self.anonymousClient = [[AFHTTPClient alloc] initWithBaseURL:baseUrl];
    [self.anonymousClient setParameterEncoding:AFJSONParameterEncoding];
    [self.anonymousClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
}

- (void)GET:(NSString *)path parameters:(NSDictionary *)params success:(SuccessCallback)sCallback error:(ErrorCallback)eCallback {

    [_secureClient getPath:path
                parameters:params
                   success:^(AFHTTPRequestOperation *operation, id responseObject) {
                       DDLogVerbose(@"Success Path: %@ JSON: %@", path, responseObject);
                       if (sCallback) sCallback(responseObject);
                   }
                   failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                       [Rest callErrorBlock:eCallback withOperation:operation];
                   }];
}

@end

Model Access Layer 模型访问层

@interface Model

+ (Model *)shared;
- (void)appsForLocation:(Location *)location success:(SuccessCallback)success error:(ErrorCallback)error;

@end

@implementation Model

- (void)appsForLocation:(Location *)location success:(SuccessCallback)success error:(ErrorCallback)error {
    NSString *path = [NSString stringWithFormat:@"/api/locations/%@/apps/", location.locationId];

    [[Rest sharedClient] GET:path parameters:nil success:success error:error];
}

@end

A Location is a root object in the application and it will be told to refresh often. 位置是应用程序中的根对象,将被告知经常刷新。 Either through UI interaction, events, or data Deserialization the the refreshApplications will execute to get more data from the server. 通过UI交互,事件或数据反序列化,refreshApplications将执行以从服务器获取更多数据。 Meanwhile other requests and events are going on in the application to get and send data to the API is JSON. 同时,其他请求和事件正在应用程序中进行,以获取和发送数据到JSON。 Some of these GET calls to other endpoints seem to be messing with the response data. 这些对其他端点的GET调用中似乎有些混乱了响应数据。

Questions 问题

  1. How could this be happening with AFNetworking? AFNetworking怎么会这样?
  2. Am I being too quick to blame AFNetowrking and should I be looking for other places in my system that could be crossing the responses? 我是否太过责怪AFNetowrking了吗?我是否应该在系统中寻找其他可能跨越响应的地方? I do have a load balanced backend hosted at Amazon. 我确实在Amazon托管了一个负载平衡后端。
  3. Is this an endpoint issue? 这是端点问题吗?
  4. How can I better debug and reproduce this issue? 如何更好地调试和重现此问题? It only comes up at random times and is very hard to replicate. 它仅在随机时间出现,并且很难复制。 I have to continually run and re-run the application in hopes that it is crash. 我必须不断运行并重新运行该应用程序,以希望它崩溃。
  5. Are there any advanced debugging techniques that I can use to back trace this call/crash using xcode? 是否可以使用xcode追溯跟踪此调用/崩溃的任何高级调试技术?

I recommend that you use Charles proxy to double-check that the data you're receiving is correct. 我建议您使用Charles代理仔细检查接收的数据是否正确。 There's a trial version available that works identically to the registered version for 30 days. 提供30天的试用版,与注册版相同。 My first guess is that there's either some sort of buggy cache layer between you and your server, or your server is buggy. 我的第一个猜测是您和您的服务器之间存在某种错误的缓存层,或者您的服务器错误。 An HTTP proxy like Charles will allow you to confirm or reject this hypothesis. 像Charles这样的HTTP代理将允许您确认或拒绝该假设。

This page explains how to set up Charles to proxy non-HTTPS connections from iOS devices. 本页说明如何设置Charles来代理来自iOS设备的非HTTPS连接。

To debug non-HTTPS as well as HTTPS Traffic use the mitmproxy 要调试非HTTPS以及HTTPS流量,请使用mitmproxy

It allows you to inspect all packages and also resend them and much more. 它使您可以检查所有软件包,还可以重新发送它们等等。 With this you can check what really happens and if the backend is the problem or if AFNetworking has a Bug. 使用此工具,您可以检查实际发生的情况以及后端是否有问题或AFNetworking是否存在错误。

And as a cool side effect mitmproxy is totally free and Open-Sourced under the MIT Licensed. 作为一个很酷的副作用, mitmproxy是完全免费的,并且根据MIT许可是开放源代码的。 On their website you will find some handy tutorials specific for iOS. 在他们的网站上,您将找到一些专门针对iOS的便捷教程。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM