Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

expected content type text/json got text/html

I am developing a web service, and am writing a register / login API. When I try and register in the iOS simulator, I get "expected content type text/json got text/html." I have spent hours now trying to debug and find the problem, but am not seeing why I am not getting JSON data.

API.h

#import "AFHTTPClient.h"
#import "AFNetworking.h"

typedef void (^JSONResponseBlock)(NSDictionary* json);

@interface API : AFHTTPClient

@property (strong, nonatomic) NSDictionary *user;

+ (API *)sharedInstance;

//check whether there's an authorized user
-(BOOL)isAuthorized;

//send an API command to the server
-(void)commandWithParams:(NSMutableDictionary*)params onCompletion:(JSONResponseBlock)completionBlock;

@end

API.m

#import "API.h"

#define kAPIHost @"http://localhost"
#define kAPIPath @"/api/"

@implementation API

@synthesize user;

+(API*)sharedInstance
{
    static API *sharedInstance = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        sharedInstance = [[self alloc] initWithBaseURL:[NSURL URLWithString:kAPIHost]];
    });

    return sharedInstance;
}

-(API*)init
{
    //call super init
    self = [super init];

    if (self != nil) {
        //initialize the object
        user = nil;

        [self registerHTTPOperationClass:[AFJSONRequestOperation class]];

        // Accept HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.1
        [self setDefaultHeader:@"Accept" value:@"application/json"];
    }

    return self;
}

-(BOOL)isAuthorized
{
    return [[user objectForKey:@"user_id"] intValue]>0;
}

-(void)commandWithParams:(NSMutableDictionary*)params onCompletion:(JSONResponseBlock)completionBlock
{
    NSMutableURLRequest *apiRequest =
    [self multipartFormRequestWithMethod:@"POST"
                                    path:@"http://localhost/api/index.php"
                              parameters:params
               constructingBodyWithBlock: ^(id <AFMultipartFormData>formData) {
                   //TODO: attach file if needed
               }];

    AFJSONRequestOperation* operation = [[AFJSONRequestOperation alloc] initWithRequest: apiRequest];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
        //success!
        completionBlock(responseObject);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        //failure :(
        completionBlock([NSDictionary dictionaryWithObject:[error localizedDescription] forKey:@"error"]);
    }];

    [operation start];
}

@end

index.php

<?
session_start();

require("lib.php");

header("Content-Type:application/json");

switch ($_POST['command'])
{
    case "login":
        login($_POST['username'],$_POST['password']);
        break;
    case "register";
        register($_POST['username'],$_POST['password']);
        break;
}

lib.php

<?php
$link = mysqli_connect("localhost","root","root");
mysqli_select_db($link,"test");

header("Content-Type:application/json");

function errorJson($msg){ 
    print json_encode(array('error'=>$msg));
    exit();
}

function register($user, $pass) {

    //check if username exists in the database (inside the "users" table)
    $login = query("SELECT username FROM users WHERE username='%s' limit 1", $user);

    if (count($login['result'])>0) {

        //the username exists, return error to the iPhone app
        errorJson('Username already exists');
    }

    //try to insert a new row in the "users" table with the given username and password
    $result = query("INSERT INTO users(username, password) VALUES('%s','%s')", $user, $pass);

    if (!$result['error']) {
        //registration is susccessfull, try to also directly login the new user
        login($user, $pass);
    } else {
        //for some database reason the registration is unsuccessfull
        errorJson('Registration failed');
    }

}

CDRegisterViewController.m

- (IBAction)signUp:(id)sender
{
    // form fields validation
    if (self.usernameField.text.length < 4 || self.passwordField.text.length < 4){
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Your password is too short" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil, nil];
        [alertView show];
    }

    // salt the password
    NSString *saltedPassword = [NSString stringWithFormat:@"%@%@", self.passwordField.text, kSalt];

    // prepare hashed storage
    NSString *hashedPassword = nil;
    unsigned char hashedPasswordData[CC_SHA1_DIGEST_LENGTH];

    //hash the pass
    NSData *data = [saltedPassword dataUsingEncoding:NSUTF8StringEncoding];
    if (CC_SHA1([data bytes], [data length], hashedPasswordData)) {
        hashedPassword = [[NSString alloc] initWithBytes:hashedPasswordData length:sizeof(hashedPasswordData) encoding:NSASCIIStringEncoding];
    } else {
        UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Password couldn't be sent" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil, nil];
        [alertView show];
        return;
    }

    // set the parameters to post
    NSString *command = @"register";
    NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:command, @"command",
                                   self.usernameField.text, @"username", hashedPassword, @"password", nil];

    // make the call to the api
    [[API sharedInstance] commandWithParams:params onCompletion:^(NSDictionary *json)
    {
        //result returned
        NSDictionary* res = [[json objectForKey:@"result"] objectAtIndex:0];

        if ([json objectForKey:@"error"]==nil && [[res objectForKey:@"IdUser"] intValue]>0) {
            //success
            [[API sharedInstance] setUser: res];
            [self.presentingViewController dismissViewControllerAnimated:YES completion:nil];

            //show message to the user
            [[[UIAlertView alloc] initWithTitle:@"Logged in"
                                        message:[NSString stringWithFormat:@"Welcome %@",[res objectForKey:@"username"] ]
                                       delegate:nil
                              cancelButtonTitle:@"Close"
                              otherButtonTitles: nil] show];

        } else {
            //error
            UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Error" message:[json objectForKey:@"error"] delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:nil, nil];
            [alertView show];
        }
    }];
}
like image 279
jsmos Avatar asked Feb 12 '14 20:02

jsmos


1 Answers

Have you looked at the data to/from the service with an analyzer such as Charles Proxy? That would be the first step--figure out if the problem is on the server or iOS. Next provide some data, the request and the response. Find the end that is incorrect and fix.

like image 71
zaph Avatar answered Oct 13 '22 16:10

zaph