Здравствуйте!
Пробую подключиться к сервисам Wialon по Remote API.
Программа на С++, в частности на C++ Builder 6.
Пробовал использовать как сокеты так и Indy-компоненты.
Код (часть кода, отвечающая за посылку запроса серверу и прием) следующий:
void __fastcall TForm1::Button5Click(TObject *Sender)
{
TStringList *s = new TStringList;
TMemoryStream *fs = new TMemoryStream();
AnsiString Request = "params={\"user\":\"apitest\",\"password\":\"apitest\"}";
Memo2->Lines->Add(AnsiToUtf8(Request));
s->Clear();
s->Add(AnsiToUtf8(Request));
IdHTTP1->Request->ContentLength = Request.Length();
IdHTTP1->Post("/wialon/ajax.html?svc=core/login", s, fs);
fs->SaveToFile("in.txt");
s->Clear();
s->LoadFromFile("in.txt");
for(int i=0; i<s->Count; ++i) Memo2->Lines->Add(Utf8ToAnsi(s->Strings[i]));
delete fs;
delete s;
}
В результате от сервера приходит:
Примерно то же самое происходит и при работе через сокет:
void __fastcall TForm1::BTestClick(TObject *Sender)
{
AnsiString Params =
"svc=core/login¶ms={user:apitest,password:apitest}";
AnsiString Request =
"POST /wialon/ajax.html HTTP/1.1\r\n\
Content-Length: "+IntToStr(Params.Length())+"\r\n\
Host: testing.wialon.com\r\n\
\r\n"
+Params+
"\r\n";
//пробовал добавлять это в запрос:
//Accept: application/jsonrequest\r\n\
//Content-Encoding: identity\r\n\
//Content-Type: application/jsonrequest\r\n\
//svc=core/login¶ms=%7Buser%3Aapitest%2Cpassword%3Aapitest%7D\r\n\
Memo1->Lines->Add(Request);
if(!ClientSocket1->Socket->Connected)
{
ClientSocket1->Open();
}
for(int i=0; i<5; ++i) ClientSocket1->Socket->SendText("\r\n"); //???
ClientSocket1->Socket->SendText(Request);
//ClientSocket1->Socket->SendText(AnsiToUtf8(Request));
}
Результат с сервера:
HTTP/1.1 200 OK
Date: Wed, 14 Nov 2012 12:32:04 GMT
Content-Type: application/json
Connection: keep-alive
Cache-Control: no-cache
Content-Length: 12
Server: adf_http_server/4.3.0182
{"error":4}
Что я делаю неправильно?
Если возможно, дайте, пожалуйста, примеры вызовов RemoteAPI на C или С++.
UPD: Ситуация меняется к лучшему если передавать POST-запрос с пустым телом или, как в нижеследующем примере, состоящим из одного символа, а параметры передавать в URL.
То есть если вместо строк
AnsiString Request = "params={\"user\":\"apitest\",\"password\":\"apitest\"}";
и
IdHTTP1->Post("/wialon/ajax.html?svc=core/login", s, fs);
вставить строки
AnsiString Request = "";//пустое тело POST-запроса с Content-Length == 0
и
IdHTTP1->Post("/wialon/ajax.html?svc=core/login¶ms={\"user\":\"apitest\",\"password\":\"apitest\"}", s, fs); //параметры - прямо в URL
соответственно, то все начинает работать.
UPD2: Проблема также решается если указать в заголовках тип контента Content-Type: application/x-www-form-urlencoded:
IdHTTP1->Request->ContentType = "application/x-www-form-urlencoded";
для Indy-компонента, и
AnsiString Params =
"svc=core/login¶ms={user:apitest,password:apitest}";
AnsiString Request =
"POST /wialon/ajax.html HTTP/1.1\r\n\
Content-Type: application/x-www-form-urlencoded\r\n\
Content-Length: "+IntToStr(Params.Length())+"\r\n\
Host: testing.wialon.com\r\n\
\r\n"
+Params+
"\r\n";
для сокета.
Правильно ли это? Правильное ли это решение?
Как быть с остальными запросами API?
Пытаться передать их в теле POST-а или в URL?
Какой тип контента необходимо указывать?