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];
}
}];
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With