Ошибка типа контента AFNetworking версии 2

Я пытаюсь создать приложение для iphone, которое будет взаимодействовать с определенным сервером JIRA. У меня есть следующий код для входа:

NSURL *url = [[NSURL alloc] initWithString:@"https://mycompany.atlassian.net/rest/auth/latest/session/"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
NSString *postString = [NSString stringWithFormat:@"{\"username\":\"%@\",\"password\":\"%@\"}", username, password];
[request setHTTPBody:[postString dataUsingEncoding:NSUTF8StringEncoding]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[request setValue:@"application/json" forHTTPHeaderField:@"Accept" ];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
[operation setCompletionBlockWithSuccess:
    ^(AFHTTPRequestOperation *operation, id responseObject) {
        NSLog(@"JSON: %@", responseObject);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"ERROR: %@", error);

    }
 ];
 [operation start];

Но это дает мне следующую ошибку, связанную с Content-Type:

ERROR: Error Domain=AFNetworkingErrorDomain Code=-1011
"Request failed: unsupported media type (415)"
UserInfo=0x8cd6540
{
  NSErrorFailingURLKey=https://mycompany.atlassian.net/rest/auth/latest/session/,
  NSLocalizedDescription=Request failed: unsupported media type (415),
  NSUnderlyingError=0x8c72e70
  "Request failed: unacceptable content-type: text/html", 

Я не уверен, в чем проблема. Я нашел этот вопрос, который, по моему мнению, может быть аналогичная проблема, но в ответах говорится либо использовать класс AFJSONRequestOperation (что я не могу, потому что я использую AFNetworking версии 2, в которой нет этого класса), либо исправить его на стороне сервера (что я также могу не по понятным причинам).

Что я могу исправить эту ошибку, если я не могу исправить серверную часть и не могу использовать AFJSONRequestOperation?


person James Dunn    schedule 23.01.2014    source источник
comment
Рад, что вы решили свою проблему. Кстати, не рекомендуется создавать JSON с stringWithFormat (если пароль содержит определенные символы, он не будет работать). Лучше использовать NSDictionary *postDictionary = @{@"username":username,@"password":password};, а затем использовать NSData *postBody = [NSJSONSerialization dataWithJSONObject:postDictionary options:0 error:&error]; для создания NSData для setHTTPBody. Или в AF 2.0 используйте POST и AFJSONRequestSerializer (в AF 1.x используйте AFHTTPClient с parameterEncoding из AFJSONParameterEncoding), и он преобразует словарь в JSON для вас.   -  person Rob    schedule 24.01.2014


Ответы (5)


Если вы используете AFNetworking 2.0, вы можете использовать метод POST, который немного упрощает:

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.requestSerializer = [AFJSONRequestSerializer serializer];
NSDictionary *parameters = @{@"username":username, @"password":password};
[manager POST:@"https://mycompany.atlassian.net/rest/auth/latest/session/" parameters:parameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"JSON: %@", responseObject);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"Error: %@", error);
}];

Это создает запрос, устанавливает его Content-Type в соответствии с настройкой requestSerializer и кодирует JSON для вас. Одним из преимуществ AFNetworking является то, что вы можете избавиться от ручного создания и настройки NSURLRequest объектов.


Кстати, ошибка «Ошибка запроса: неприемлемый тип содержимого: текст/html» означает, что независимо от того, что вы ожидали получить (например, JSON), вы получили ответ в формате HTML. Это очень распространено: многие ошибки сервера (например, сервер сообщает вам, что запрос был неправильно сформирован и т. д.) генерируют сообщения об ошибках в формате HTML. Если вы хотите увидеть этот HTML-код в своем блоке failure, просто запишите файл operation.responseString.

person Rob    schedule 23.01.2014
comment
Вы спасли мой день. Спасибо. - person chancyWu; 16.05.2015

Оказывается, проблема в том, что эта одна строка:

[request setValue:@"application/json" forHTTPHeaderField:@"Accept" ];

Должно быть

[request setValue:@"application/json" forHTTPHeaderField:@"Content-Type" ];

Теперь ошибка устранена. (Правка: у меня должно быть и то, и другое, см. комментарий CouchDeveloper.)

ИЗМЕНИТЬ
Решение Роба лучше, поэтому я использую его. На самом деле я пробовал решение, похожее на то, что он показывает, но там, где у него была линия,

manager.requestSerializer = [AFJSONRequestSerializer serializer];

У меня была строка:

[manager.requestSerializer
    setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];

... что не сработало. Спасибо Робу за то, что заставил его работать!

person James Dunn    schedule 23.01.2014
comment
Вам может понадобиться и то, и другое: с заголовком Accept вы указываете, какой тип медиа вы хотите получить, когда есть ответ. С заголовком Content-Type вы указываете тип носителя, который вы отправляете. Заголовок Content-Type ДОЛЖЕН (действительно должен) быть указан в вашем запросе. - person CouchDeveloper; 24.01.2014
comment
@CouchDeveloper Спасибо, это помогает мне лучше понять это. - person James Dunn; 24.01.2014

У меня была такая же проблема в AFNetworking 2.0, и решение заключалось в том, что я должен был убедиться, что я установил тип AFHTTPRequestSerializer (если ваш запрос - JSON), он должен быть таким.

AFHTTPSessionManager *myHTTPManager = ...
[myManager setRequestSerializer:[AFJSONRequestSerializer serializer]];

Вы должны установить оба AFHTTPResponseSerializer и AFHTTPRequestSerializer

person Ali Amin    schedule 05.04.2014

если вы используете письменный класс по умолчанию AFAppDotNetAPIClient и сталкиваетесь с этой ошибкой. Необходимо добавить responseSerializer. см., как должен выглядеть ваш общий метод -

+ (instancetype)sharedClient {

static AFAppDotNetAPIClient *_sharedClient = nil;
static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{
    _sharedClient = [[AFAppDotNetAPIClient alloc] initWithBaseURL:[NSURL URLWithString:AFAppDotNetAPIBaseURLString]];
    _sharedClient.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone];
    _sharedClient.responseSerializer = [AFHTTPResponseSerializer serializer];
});
return _sharedClient;}
person Prakash Raj    schedule 22.07.2014

Используйте эту строку кода.

operation.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];
person Om Prakash    schedule 17.07.2015