Я разрабатываю веб-службу для обслуживания объектов json в асинхронном дереве jeasyui. . Мой HTML имеет следующее:
<ul id="tt" method="POST" class="easyui-tree" url="http://w.x.y.z:1024/testrest">
</ul>
Предположим, что w.x.y.z — это IP-адрес моего сервера. Согласно документации jeasyui для их службы PHP json, мне нужно вернуть массив объектов словаря с ключами id
, text
и state
. Ладно, пока все хорошо. Я пытаюсь разработать службу json на С++, используя cpprest-sdk от Microsoft. Я скомпилировал и установил эту библиотеку на RHEL 7.2 и могу писать с ее помощью некоторые базовые службы. Проблема заключается (я думаю) в кодировке json, который отправляется обратно клиенту.
Вот полнофункциональный пример json-сервера, написанный с помощью cpprest-sdk, который обрабатывает POST-запросы и ответы с однократно заполненным массивом объектов словаря, которые соответствуют протоколу, ожидаемому jeasyui:
#include <cpprest/http_listener.h>
#include <cpprest/json.h>
#pragma comment(lib, "cpprestlib" )
using namespace web;
using namespace web::http;
using namespace web::http::experimental::listener;
#include <iostream>
#include <map>
#include <set>
#include <string>
using namespace std;
#define TRACE(msg) wcout << msg
void handle_request(http_request request, function<void(const json::value &, json::value &, bool)> action)
{
json::value answer;
TRACE("\nHandle_request\n");
// Spit out the HTTP header to the console...
const auto HeaderString = request.to_string();
wcout << HeaderString.c_str() << endl;
request
.extract_json()
.then([&answer, &action](pplx::task<json::value> task) {
try
{
const auto & jvalue = task.get();
if (!jvalue.is_null())
{
action(jvalue, answer, false);
}
else
{
action(jvalue, answer, true);
}
}
catch (http_exception const & e)
{
wcout << "HTTP exception in handle_request: " << e.what() << endl;
}
})
.wait();
request.reply(status_codes::OK, answer);
}
void handle_post(http_request request)
{
TRACE("\nHandle POST\n");
handle_request(
request,
[](const json::value & jvalue, json::value & answer, bool bNull)
{
const utility::string_t sID("id");
const utility::string_t sText("text");
const utility::string_t sState("state");
if( bNull )
{
wcout << "jvalue must be null, setting some default values..." << endl;
json::value group;
group[sID] = json::value::string("1");
group[sText] = json::value::string("Hello");
group[sState] = json::value::string("closed");
answer[0] = group;
}
else
{
// To be written once the null case is sorted
}
}
);
}
int main()
{
uri_builder uri("http://w.x.y.z:1024/testrest");
http_listener listener(uri.to_uri());
listener.support(methods::POST, handle_post);
try
{
listener
.open()
.then([&listener]()
{
TRACE(L"\nStarting to listen\n");
})
.wait();
while (true);
}
catch (exception const & e)
{
wcout << e.what() << endl;
}
return 0;
}
Это компилируется чисто, и я могу запустить службу на сервере Linux со следующим:
./testrest &
Starting to listen
Чтобы помочь в отладке, я использовал curl
в качестве POST-клиента непосредственно на том же сервере Linux. Я использовал следующую команду для отправки запроса POST с нулевой длиной содержимого:
curl -i -X POST -H 'Content-Type: application/json' http://w.x.y.z:1024/testrest
Вывод из curl следующий:
HTTP/1.1 200 OK
Content-Length: 44
Content-Type: application/json
[{"id":"1","state":"closed","text":"Hello"}]
и консольные сообщения от моей службы такие:
Handle POST
Handle_request
POST /testrest HTTP/1.1
Accept: */*
Content-Type: application/json
Host: w.x.y.z:1024
User-Agent: curl/7.29.0
jvalue must be null, setting some default values...
Первые две строки соответствуют вызовам TRACE
в коде. Средний раздел генерируется этим разделом кода:
// Spit out the HTTP header to the console...
const auto HeaderString = request.to_string();
wcout << HeaderString.c_str() << endl;
Основываясь на выводе curl, который представляет собой массив объектов словаря длиной ровно в одну запись, я ожидаю, что этот сервис будет отлично работать с jeasyui javascript на клиенте. Однако это не так. Мое асинхронное дерево никогда не заполняется, и я вообще ничего не вижу.
Я подозреваю, что что-то не так с кодировкой, поэтому я написал еще один сервис, используя web2py, чтобы проверить, будет ли он там работать. В моем контроллере default.py существует следующий код:
@service.json
def testweb2py():
aRet=[]
if request.post_vars.id is None:
mydict={'id':'1','text':'Hello','state':'closed'}
aRet.append(mydict)
return aRet
после изменения моего клиента easyui-tree
HTML, чтобы он указывал на URL-адрес web2py, он отлично заполняется, и я вижу узел. Я нажал на код web2py service.json с помощью curl, просто чтобы посмотреть, как результат может отличаться:
HTTP/1.1 200 OK
Date: Mon, 23 Jan 2017 18:17:17 GMT
Server: Apache/2.4.6 (Red Hat Enterprise Linux) OpenSSL/1.0.1e-fips mod_wsgi/3.4 Python/2.7.5
X-Powered-By: web2py
Expires: Mon, 23 Jan 2017 18:17:18 GMT
Pragma: no-cache
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Content-Length: 99
Content-Type: application/json; charset=utf-8
[{"text": "Hello", "state": "closed", "id": "1"}]
Помимо того, что заголовок содержимого совершенно другой, есть одна строка, которая, как я подозреваю, может иметь к этому какое-то отношение:
Content-Type: application/json; charset=utf-8
При вызове службы cpprest вывод заголовка из curl не включает в себя charset=utf-8
. Если я сброшу вывод curl в файл с помощью переключателя -o
, я не увижу четкой разницы между кодировкой. Единственное, что я вижу в формате json, — это дополнительные пробелы и порядок:
[{"text": "Hello", "state": "closed", "id": "1"}] // web2py version
[{"id":"1","state":"closed","text":"Hello"}] // cpprest version
Я не могу получить какой-либо контроль над порядком отправки словаря json, но я сомневаюсь, что это как-то связано с этим. Дополнительный пробел перед записью значения также кажется неуместным.
Я изучил документацию cpprest по адресу microsoft.github.io/cpprestsdk/index.html и не могу найти ничего, что касалось бы настройки выходной кодировки. Существует ряд переопределений для http_request::reply
, которые включают параметры для установки типа содержимого, и я пошел по пути вызова их с жестко закодированными строками как для тела json, так и для типа содержимого json/application; charset=utf-8
, все безрезультатно. . Я не понимаю, как эти переопределения можно использовать с объектами json::value в любом случае, поэтому я не думаю, что это оптимальный путь или жизнеспособное использование этой библиотеки cpprest.
Код javascript jeasyui кажется намеренно запутанным, и я мало верю в то, что смогу понять, что он делает с ответом на вызов POST. Может быть, кто-то, знакомый с jeasyui, может указать жизнеспособное средство для отладки асинхронного POST?
Пожалуйста помоги!