Я застрял в проблеме и ищу идеи относительно лучшего способа ее решения.
Я занялся разработкой сайта, на котором бэкэнд написан на Perl, а во внешнем интерфейсе широко используется javascript.
Клиент регулярно получает обновление нескольких сотен отслеживаемых объектов из серверной части. Объекты отображаются на карте Google с помощью JavaScript. Хеш объекта (анализируемый JavaScript) содержит много информации об объекте, например, местоположение, описание и различные переменные состояния.
Некоторые данные представлены в виде строк, а некоторые числовыми.
Проблема в том, что в процессе отправки данных на клиентский JavaScript все значения становятся строками. И так, в javascript, если я проверяю, например, чтобы увидеть, является ли значение положительным, тест проходит успешно, даже если значение равно 0, потому что значение на самом деле «0», а не 0.
На стороне сервера данные кодируются с помощью JSON :: XS следующим образом;
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} );
} ## end of: sub process_json
На стороне клиента данные декодируются с помощью JSON.parse следующим образом:
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({});
}
}
}
}
}
Может кто-нибудь увидеть полезный способ решения этой проблемы? Perl не является строго типизированным, и JSON :: XS просто анализирует числовые данные в виде строки, а не числа. Я попытался добавить reviver в JSON.parse (см. Код ниже) - однако он не работает (он обрабатывает большую часть данных правильно, но продолжает работать с различными сообщениями, такими как non_object_property_call или undefined_method.
Независимо от того, было бы предпочтительно, если бы работа парсинга данных для обеспечения правильного типа была обработана на стороне сервера. Кто-нибудь может увидеть, как это может быть эффективно достигнуто?
function toNum(key, value) {
/*make sure value contains an integer or a float not a string */
/*TODO: This seems VERY inefficient - is there a better way */
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;
}
}