У меня есть URL-адрес API, который возвращает данные JSON следующим образом:
{"data":[{"id":"1","param":"value1"},{"id":"2","param":"value2"}, ... {"id":"N","param":"valueN"}]}
Каждый id
должен быть уникальным.
Когда я запрашиваю этот URL-адрес API через браузер (Firefox или Chrome), он возвращает достоверные данные, т. id
Каждый id
уникален, а дубликаты частей данных дублируются.
Но когда я запрашиваю этот URL API через мою собственную функцию на основе WinInet
он дублирует некоторые части данных. Он по-прежнему действителен JSON, но некоторые id
дублируются, а некоторые из них нет. Именно так:
{"data":[{"id":"1","param":"value1"},{"id":"1","param":"value1"},{"id":"2","param":"value2"},{"id":"3","param":"value3"},{"id":"3","param":"value3"} ... {"id":"N","param":"valueN"}]}
Я использую метод GET. Вот моя функция WinInet
:
using namespace std;
enum EMethod {M_UNKNOWN, M_POST, M_GET, M_DELETE};
enum EProtocol {P_UNKNOWN, P_HTTP, P_HTTPS};
// |example:|
/*
string responce = SendInetRequest(
P_HTTPS, M_GET, "www.site.com", "page.php", "param1=val1¶m2=val2");
*/
string SendInetRequest(const EProtocol _eProtocol,
const EMethod _eMethod,
const string& _server,
const string& _page,
const string& _params = "")
{
char szData[1024];
string recvStr;
// initialize WinInet
HINTERNET hInternet = ::InternetOpenA("WinInet Test",
INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
if (hInternet != NULL)
{
INTERNET_PORT port = NULL;
DWORD flags = NULL;
switch (_eProtocol)
{
case P_HTTP:
port = INTERNET_DEFAULT_HTTP_PORT;
flags = /*INTERNET_FLAG_KEEP_CONNECTION*/
INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_PRAGMA_NOCACHE;
break;
case P_HTTPS:
port = INTERNET_DEFAULT_HTTPS_PORT;
flags = INTERNET_FLAG_SECURE |
INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_PRAGMA_NOCACHE;
break;
default:
return NULL;
}
// open HTTP session
HINTERNET hConnect = ::InternetConnectA(hInternet,
_server.c_str(), port, NULL,NULL, INTERNET_SERVICE_HTTP, 0, 1);
if (hConnect != NULL)
{
string request;
string method;
string headers;
string data;
switch (_eMethod)
{
case M_GET:
method = "GET";
request = _page +
(_params.empty() ? "" : ("?" + _params));
break;
case M_POST:
method = "POST";
request = _page;
headers = "Content-Type: application/x-www-form-urlencoded";
data = _params.empty() ? "" : _params;
break;
case M_DELETE:
method = "DELETE";
request = _page +
(_params.empty() ? "" : ("?" + _params));
break;
default:
return NULL;
}
// open request
HINTERNET hRequest = ::HttpOpenRequestA(hConnect, method.c_str(),
(LPCSTR)request.c_str() ,NULL, NULL, 0, flags, 1);
if (hRequest != NULL)
{
// send request
BOOL isSend = ::HttpSendRequestA(hRequest, headers.c_str(),
headers.length(), (LPVOID)data.c_str(), data.length());
if (isSend)
{
for(;;)
{
// reading data
DWORD dwByteRead;
BOOL isRead = ::InternetReadFile(hRequest,
szData, sizeof(szData) - 1, &dwByteRead);
// break cycle if error or end
if (isRead == FALSE || dwByteRead == 0)
break;
// saving result
recvStr.append(szData, dwByteRead);
szData[dwByteRead] = 0;
}
}
// close request
::InternetCloseHandle(hRequest);
}
// close session
::InternetCloseHandle(hConnect);
}
// close WinInet
::InternetCloseHandle(hInternet);
}
return recvStr;
}
Так что же не так с моей функцией? Почему он дублирует некоторые части данных JSON-ответа, в отличие от обычных браузеров?
Вам нужно добавить байт null terminator в szData
прежде чем добавлять его в recvStr
, чтобы вы только добавляли только что полученные данные.
// saving result
szData[dwByteRead] = 0;
recvStr.append(szData, dwByteRead);
append
. Я не уверен, откуда происходит дублирование.