2


I don't know if this is a Node.js or an iOS problem, but when I try to send a JSON object which contains umlauts (ä, ö, and ü) the set content-length seems to be wrong.

So here's my setup:

My Node.js server sends data via:

[..mongodb request..].toArray(function(err, result) {
    res.setHeader('Content-Type', 'application/json');
    var body = JSON.stringify(result);

    console.log(body);
    console.log(body.length);

    res.setHeader('charset', 'utf8');
    res.setHeader('Content-Length', body.length);
    res.end(body);
});

This yields the following object:

[
{
    "_id": "51da7eb5d5f9ad77302a26c6",
    "loc": [
        53.560994,
        9.929796
    ],
    "street": "Kühnehöfe 25",
    "time": 1373273781535
},
{
    "_id": "51da7eb9d5f9ad77302a26c7",
    "loc": [
        53.561899,
        9.930203
    ],
    "street": "Kühnehöfe 17",
    "time": 1373273785156
}
]

Which has (parsed as string) a length of 215. This is also set as the content length.

In my iOS project I've got following setup:

-(void)serverRequest {

    // Initialize new mutable data
    NSMutableData *data = [[NSMutableData alloc] init];
    self.receivedData = data;

    // Initialize URL that is going to be fetched.
    NSURL *url = [NSURL URLWithString:@"http://localhost:8000/getSpots"];

    // Initialize a request from a URL
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[url standardizedURL]];

    // Set HTTP method
    [request setHTTPMethod:@"POST"];

    // Initialize post data
    NSDictionary* jsonDict = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithFloat:coordinate.latitude], @"lat", [NSNumber numberWithFloat:coordinate.longitude], @"lng", accessToken, @"accessToken", nil];//dictionaryWithObjectsAndKeys:coord.latitude, nil]
    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:jsonDict
                                                   options:NSJSONWritingPrettyPrinted // Pass 0 if you don't care about the readability of the generated string
                                                     error:&error];

    // Set request content type we MUST set this value.
    [request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"content-type"];

    // Set post data of request
    [request setHTTPBody:jsonData];

    // Initialize a connection from request
    NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
    self.connectionGetSpots = connection;

    // Start the connection
    [connection start];
}

-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data{
    [self.receivedData appendData:data];

    NSLog(@"loading: %d, %lld", [self.receivedData length], dataSize);  // Both 215 (correct)
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response{
    dataSize = [response expectedContentLength];
    NSLog(@"dataSize: %lld", dataSize);  // is 215 (correct)
}

-(void)connectionDidFinishLoading:(NSURLConnection *)connection{
    NSString *responseData = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding];
    NSLog(@"rD: %@, %d" ,responseData, [responseData length]);
}

The connectionDidFinishLoading function logs this:

[
{
    "_id": "51da7eb5d5f9ad77302a26c6",
    "loc": [
        53.560994,
        9.929796
    ],
    "street": "Kühnehöfe 25",
    "time": 1373273781535
},
{
    "_id": "51da7eb9d5f9ad77302a26c7",
    "loc": [
        53.561899,
        9.930203
    ],
    "street": "Kühnehöfe 17",
    "time": 13732737851
,211

As you can see, there are four umlauts in the JSON object and four characters are missing. If I add another location with two umlauts, two more characters will be missing.

I guess somewhere the content type is set wrong, but I'm not sure what I have to do.

6
  • The JSON string in your question has 315 characters (not 215). Since every umlaut is encoded as 2 UTF-8 bytes, the content length should be 319. Commented Jul 8, 2013 at 9:36
  • sorry the original string i send is: [{"_id":"51da7eb5d5f9ad77302a26c6","loc":[53.560994,9.929796],"street":"Kühnehöfe 25","time":1373273781535},{"_id":"51da7eb9d5f9ad77302a26c7","loc":[53.561899,9.930203],"street":"Kühnehöfe 17","time":1373273785156}] I formatted it for better readability Commented Jul 8, 2013 at 9:39
  • Then, your string has 231 bytes. What does your JS statement body.length return? The number of characters or the number of bytes (unlikely)? It would probably be better to ensure you are setting an array of bytes, not a string, in your request. Commented Jul 8, 2013 at 10:28
  • Yes, it returns the number of characters. Commented Jul 8, 2013 at 10:52
  • It works if I use encodeURI(body).split(/%..|./).length - 1 instead of body.length. Thanks for your help Commented Jul 8, 2013 at 10:57

1 Answer 1

4

Use this for correct UTF-8 lengths:

new Buffer(body).length
Sign up to request clarification or add additional context in comments.

2 Comments

Nice! And the encoding is per default UTF-8 ;) I'm not the OP, but wouldn't it be better to set the Buffer instance as the body of the request? Is a Content-Length header explicitly required, too?
Thanks. You would have to convert the Buffer back to String (toString('utf-8')), so there's no difference. And yes, from my experience a "Content-Length" header is indeed required.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.