I am stuck in a problem and I am looking for ideas on the best way to solve it.
I started developing a site where the backend is written in Perl, and the front end makes extensive use of javascript.
The client regularly receives updates from several hundred monitored objects from the backend. Objects are displayed on google map through javascript. An object hash (parsed by javascript) contains a lot of information about the object, for example. location, description, and various state variables.
Some data in string form and some numerical.
The problem is that in the process of pushing data on javascript on the client side, all values ββbecome strings. So, in javascript, if I test, for example, to make sure the value is positive, the test succeeds even if the value is 0, because the value is actually "0", not 0.
On the server side, the data is encoded using JSON :: XS as follows:
sub process_json { my $self = shift; return if( $self->{processed} ); $self->{processed} = 1; if( $self->{requestrec}->status =~ /^3/ ) { return $self->{requestrec}->status; } $self->{data}->{session} = { id => $self->session->id, user => $self->session->{data}->{__user}, }; use utf8; my $output; eval { $output = JSON::XS->new->utf8->encode( $self->{data} ); }; if( $@ ) { use Carp; confess( $@ ); } $self->discard_request_body(); $self->req->content_type('application/json; charset=utf-8'); $self->req->headers_out->set( 'Expires' => 'Thu, 1 Jan 1970 00:00:00 GMT' ); my $out_bytes = encode( 'UTF-8', $output ); $self->req->headers_out->set( 'Content-Length' => length $output ); $self->req->print($output) unless( $self->req->header_only() ); delete $self->{session}->{data}->{errors} if( exists $self->{session}->{data}->{errors} ); delete $self->{session}->{data}->{info} if( exists $self->{session}->{data}->{info} ); }
On the client side, data is decoded using JSON.parse as follows:
function http_process (req, callback, errorfn) { if (req.readyState == 4) { this.activerequest = null; if (req.status != 200 && req.status != 0 && req.status != 304 && req.status != 403) { if (errorfn) { return errorfn(req); } else { dialogue("Server error", "Server error " + req.status); } if (req.status == 400) { dialogue("ERROR","Session expired"); this.failed = 1; } else if (req.status == 404) { dialogue("ERROR", "Server error (404)"); this.failed = 1; } else if (req.status == 500) { dialogue("ERROR", "Server error (500)"); this.failed = 1; } } else { if (callback) { if (req.responseText) { lstatus("Loaded (" + req.responseText.length + " bytes)"); warn("Received " + req.responseText.length + " bytes"); try { var obj = JSON.parse(req.responseText); } catch(e) { warn(e); warn(req.responseText); } callback( obj ); } else { callback({}); } } } }
}
Can anyone see a useful way to solve this? Perl is not strongly typed, and JSON :: XS simply parses numeric data as a string, not a number. I tried adding reviver to JSON.parse (see code below) - however, it does not work (it processes most of the data correctly, but continues to work with various messages, such as non_object_property_call or undefined_method.
Regardless, it would be preferable if the work of analyzing the data to ensure the correct type was handled on the server side. Can anyone see how this can be achieved effectively?
function toNum(key, value) { if (value instanceof Object) return; if (value instanceof Array) return; var intRE = /^\d+$/; var floatRE = /^\d*\.\d+$/; if(value.match(intRE)) { value = parseInt(value); return value; } if(value.match(floatRE)) { value = parseFloat(value); return value; }
}