Как правильно получить ответ от HTTP-сервера?
От: sushko Россия  
Дата: 24.04.16 13:37
Оценка:
Есть некоторая программа (ЕГАИС УТП), кот. позволяет с собой общаться по HTTP, при этом "задать ей вопрос" можно либо "открыв" соотв. URI и получив в ответ XML с ответом, либо за'upload'ив в нее XML с вопросами с получив в ответ XML с ответом. С первым вариантом я разобрался, а вот с XML upload беда: загрузить в нее файл у меня получается, программа факт загрузки файла отрабатывает корректно, но я никак не могу сообразить, как именно мне получить ее ответ в XML. Подскажите?

BOOL CEgais::PostXml(LPCTSTR szUri, CString sXml, CString &sError)
{
    DWORD dwResult = 0;

//  opening internet connection 
    sError.Empty();
    CInternetSession theSession("abcdef");

    CHttpConnection *pConnection = NULL;
    try
    {
        pConnection = theSession.GetHttpConnection
                                        (
                                        GetAddress(),
                                        INTERNET_FLAG_RELOAD | INTERNET_FLAG_DONT_CACHE,
                                        GetPort()
                                        );
    }
    catch (CInternetException *e)
    {
        char szError[1024];
        e->GetErrorMessage(szError, 1024);
        sError = "Не удалось соединиться с программой ЕГАИС-транспорт: " + (CString)szError;
        return FALSE;
    }

//  opening request
    CHttpFile *pFile = pConnection->OpenRequest
                                        (
                                        "POST",
                                        szUri
                                        );
    if (NULL == pFile)
    {
        sError.Format("Не удалось открыть соединение с http://%s:%d/%s", GetAddress(), GetPort(), szUri);
        pConnection->Close();
        delete pConnection;
        return FALSE;
    }

//  adding request headers
    if (!pFile->AddRequestHeaders("Content-type: multipart/form-data; boundary=1758722263496359", HSR_SYNC|HSR_INITIATE))
    {
        sError = "Не удалось добавить HTTP-заголовок при отправке запроса в ЕГАИС: " + GetSystemError(GetLastError());
        pFile->Close();
        delete pFile;
        pFile = NULL;
        pConnection->Close();
        delete pConnection;
        return FALSE;
    }

//  converting request to UTF8
    int iUtf8Length = 0;
    sXml = "\r\n--1758722263496359\r\nContent-Disposition: form-data; name=\"xml_file\";filename=\"data.xml\";\r\n\r\n" + sXml + "\r\n--1758722263496359--";
    char *utf8Contents = AnsiToUtf8((char*)(LPCTSTR)sXml, &iUtf8Length);

//  sending the request to the server
    try
    {
        pFile->SendRequestEx(iUtf8Length-1);
    }
    catch (CInternetException *e)
    {
        char szError[1024];
        e->GetErrorMessage(szError, 1024);
        sError = "Не удалось отправить запрос программе ЕГАИС-транспорт: " + (CString)szError;
        pFile->Close();
        delete pFile;
        pFile = NULL;
        pConnection->Close();
        delete pConnection;
        free(utf8Contents);
        utf8Contents = NULL;
        return FALSE;
    }

//  writing data to the request
    try
    {
        pFile->Write(utf8Contents, iUtf8Length);
    }
    catch (CException *e)
    {
        char szError[1024];
        e->GetErrorMessage(szError, 1024);
        sError = "Не удалось соединиться с программой ЕГАИС-транспорт: " + (CString)szError;
        pFile->Close();
        delete pFile;
        pFile = NULL;
        pConnection->Close();
        delete pConnection;
        free(utf8Contents);
        utf8Contents = NULL;
        return FALSE;
    }

//  closing connection and exiting
    pFile->EndRequest();
    pFile->Close();
    delete pFile;
    pFile = NULL;
    pConnection->Close();
    delete pConnection;
    pConnection = NULL;
    free(utf8Contents);
    utf8Contents = NULL;
    return TRUE;
}
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Re: Как правильно получить ответ от HTTP-сервера?
От: jahr  
Дата: 24.04.16 19:04
Оценка:
Здравствуйте, sushko, Вы писали:

S>Есть некоторая программа (ЕГАИС УТП), кот. позволяет с собой общаться по HTTP, при этом "задать ей вопрос" можно либо "открыв" соотв. URI и получив в ответ XML с ответом, либо за'upload'ив в нее XML с вопросами с получив в ответ XML с ответом. С первым вариантом я разобрался, а вот с XML upload беда: загрузить в нее файл у меня получается, программа факт загрузки файла отрабатывает корректно, но я никак не могу сообразить, как именно мне получить ее ответ в XML. Подскажите?


Ответ на POST и GET запросы читается одинаково, разница есть только при отправке данных, т.е. после pFile->Write нужно делать то же самое, что и при запросе просто по урлу (как я понимаю, это pFile->Read, конкретно на этих mfc-ишных классах это не писал, но судя по всему — именно так должно быть). Если все равно не понятно что именно делать — скажите, объясню подробнее.)
Отредактировано 24.04.2016 19:05 jahr . Предыдущая версия .
Re[2]: Как правильно получить ответ от HTTP-сервера?
От: sushko Россия  
Дата: 24.04.16 20:26
Оценка:
Здравствуйте, jahr, Вы писали:

J>Ответ на POST и GET запросы читается одинаково, разница есть только при отправке данных, т.е. после pFile->Write нужно делать то же самое, что и при запросе просто по урлу (как я понимаю, это pFile->Read, конкретно на этих mfc-ишных классах это не писал, но судя по всему — именно так должно быть). Если все равно не понятно что именно делать — скажите, объясню подробнее.)


Да нет, это понятно, только оно так не работает Т.е. при попытке pFile->Read() вдруг оказывается, что читать нечего. т.к. никто нам не пишет. В то же время CURL на тот же запрос возвращает вполне вменяемый XML ответа.
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Re[3]: Как правильно получить ответ от HTTP-сервера?
От: jahr  
Дата: 24.04.16 21:19
Оценка: 2 (1)
Здравствуйте, sushko, Вы писали:

S>Здравствуйте, jahr, Вы писали:


J>>Ответ на POST и GET запросы читается одинаково, разница есть только при отправке данных, т.е. после pFile->Write нужно делать то же самое, что и при запросе просто по урлу (как я понимаю, это pFile->Read, конкретно на этих mfc-ишных классах это не писал, но судя по всему — именно так должно быть). Если все равно не понятно что именно делать — скажите, объясню подробнее.)


S>Да нет, это понятно, только оно так не работает Т.е. при попытке pFile->Read() вдруг оказывается, что читать нечего. т.к. никто нам не пишет. В то же время CURL на тот же запрос возвращает вполне вменяемый XML ответа.


Скорее всего — при отправке данных указана неверная длина контента, тогда сервер не отвечает пока не получит того, что ему по его мнению не хватает. Длина контента указывается в соответствующем хедере. Проще всего установить какой-нибудь сниффер типа Wireshark, в котором посмотреть, что именно отправляется на сервер и сравнить с тем, что отправляет вариант с curl. Но то, что сервер не отвечает — хорошая заявка на то, что в запросе указана неверная длина данных запроса.
Re[3]: Как правильно получить ответ от HTTP-сервера?
От: jahr  
Дата: 24.04.16 21:28
Оценка:
Здравствуйте, sushko, Вы писали:

S>Да нет, это понятно, только оно так не работает Т.е. при попытке pFile->Read() вдруг оказывается, что читать нечего. т.к. никто нам не пишет. В то же время CURL на тот же запрос возвращает вполне вменяемый XML ответа.


Вот здесь ошибка :
int iUtf8Length = 0;
...
pFile->SendRequestEx(iUtf8Length-1);
Re[4]: Как правильно получить ответ от HTTP-сервера?
От: sushko Россия  
Дата: 25.04.16 08:18
Оценка:
Здравствуйте, jahr, Вы писали:

J>Скорее всего — при отправке данных указана неверная длина контента, тогда сервер не отвечает пока не получит того, что ему по его мнению не хватает. Длина контента указывается в соответствующем хедере. Проще всего установить какой-нибудь сниффер типа Wireshark, в котором посмотреть, что именно отправляется на сервер и сравнить с тем, что отправляет вариант с curl. Но то, что сервер не отвечает — хорошая заявка на то, что в запросе указана неверная длина данных запроса.


Ага, спасибо, я проверю.

J>Вот здесь ошибка :

J>int iUtf8Length = 0;
J>pFile->SendRequestEx(iUtf8Length-1);

Между этими двумя операторами стоИт:

char *utf8Contents = AnsiToUtf8((char*)(LPCTSTR)sXml, &iUtf8Length);

, кот. возвращает в OUT-параметре эту самую iUtf8Length. AnsiToUtf8() добавляет ноль в конец преобразованной строки, и отправлять этот ноль в HTTP просто незачем, поэтому в SendRequestEx() передается iUtf8Length-1.
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
Отредактировано 25.04.2016 9:47 sushko . Предыдущая версия .
Re: Как правильно получить ответ от HTTP-сервера?
От: sushko Россия  
Дата: 26.04.16 14:32
Оценка: 1 (1)
Здравствуйте, sushko, Вы писали:

Случайно нашел решение в гугле. Вместо

pFile->SendRequestEx(iUtf8Length-1);


надо было писать

pFile->SendRequestEx(iUtf8Length-1, HSR_SYNC|HSR_INITIATE);


Т.е. дело в асинхронности: когда я пытался читать ответ, реально еще не был отправлен запрос.
Бесплатный генератор отчетов для программ на C/C++
http://www.oxetta.com
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.