На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
  
    > Отправка POST запроса , Классика: отправить файл
      Доброго времени суток!

      Не сочтите за наглость: создал тему в разделе "Web технологии", но попробую спросить и тут.

      Пытаюсь залить фото на одноклассники через их API. Как показал гугл, я как и основная масса споткнулся на втором шаге: загрузка фотографий через HTTP POST.
      Если верить их документации, то мне надо отправить POST-запрос:
      ExpandedWrap disabled
        HTTP POST request
        URL : <upload URL>
        Post:
        Content-Type: multipart/form-data; boundary=---------------------------11020459624021
        Content-Length: 831083
        \\
        -----------------------------11020459624021
        Content-Disposition: form-data; name="pic1"; filename="IMG_0699.JPG"
        Content-Type: image/jpeg
        ....................
        -----------------------------11020459624021--

      <upload URL> в моем случае: https://gup.mycdn.me/uploadImage?apiToken=n...VIRuOtVRQ%3D%3D
      Для отправки использую метод, предложенный AZote: WinHTTP - POST запрос (сообщение #2246465)
      Т.е. HttpOpenRequest + HttpSendRequest (пишу на С++, MFC).
      ExpandedWrap disabled
                HINTERNET hInetSession;
                std::string strURL = "";
                std::string strStop = "";
                char cBuf[200001];
                DWORD dwRead;
                int dwReaded = 0;
            
                hInetSession = InternetOpen( "Opera/9.51 (Windows NT; U; ru)", INTERNET_OPEN_TYPE_PRECONFIG, NULL, 0, 0);
                if(!hInetSession)
                {
                    AfxMessageBox("---2");
                    return;
                }
            
                HINTERNET hConnect = InternetConnect(hInetSession, "gup.mycdn.me", INTERNET_DEFAULT_HTTP_PORT, NULL,NULL,
                    INTERNET_SERVICE_HTTP, 0, 1u);
                if(!hConnect)
                {
                    InternetCloseHandle(hInetSession);
                    AfxMessageBox("---3");
                    return;
                }
            
                strURL = "/uploadImage?apiToken=aciB5aM%2FxsI4WkCnuN4RFAczLBxVBX2mkYUhngQh7efNbHN7YzG5rWPOy7Ww%2BEblzo1db%2FegAC50yepo3agiKsudaYwrL7xfYbaA8ydctS7WNO2butBhsw%3D%3D&photoIds=Ba9z4BfOlNoTe6%2FVJyahKlpqGliqCyVrUdEynq628FB6IVP%2FRwvqVQ%3D%3D";
            
                HINTERNET hRequest = HttpOpenRequest(hConnect, "POST", strURL.c_str(), NULL, NULL, 0, INTERNET_FLAG_KEEP_CONNECTION, 1); // Пост запрос
                if(!hRequest)
                {
                    InternetCloseHandle(hConnect);
                    InternetCloseHandle(hInetSession);
                    AfxMessageBox("---4");
                    return;
                }
            
                BOOL bSend; std::string strAdd;
                strAdd = "Content-Type: multipart/form-data; boundary=---------------------------11020459624021"; // Тип контента
                bSend = ::HttpAddRequestHeaders(hRequest, strAdd.c_str(), strAdd.length(), HTTP_ADDREQ_FLAG_ADD); // Добавляем необходимые параметры запроса
                strAdd = "Content-Length: 921";
                bSend = ::HttpAddRequestHeaders(hRequest, strAdd.c_str(), strAdd.length(), HTTP_ADDREQ_FLAG_ADD);
                strAdd = "\\";
                bSend = ::HttpAddRequestHeaders(hRequest, strAdd.c_str(), strAdd.length(), HTTP_ADDREQ_FLAG_ADD);
                strAdd = "-----------------------------11020459624021";
                bSend = ::HttpAddRequestHeaders(hRequest, strAdd.c_str(), strAdd.length(), HTTP_ADDREQ_FLAG_ADD);
                strAdd = "Content-Disposition: form-data; name=\"pic1\"; filename=\"d:\\MyVC++\\~BackupOK\\1.JPG\"";
                bSend = ::HttpAddRequestHeaders(hRequest, strAdd.c_str(), strAdd.length(), HTTP_ADDREQ_FLAG_ADD);
                strAdd = "Content-Type: image/jpeg";
                bSend = ::HttpAddRequestHeaders(hRequest, strAdd.c_str(), strAdd.length(), HTTP_ADDREQ_FLAG_ADD);
                strAdd = "....................";
                bSend = ::HttpAddRequestHeaders(hRequest, strAdd.c_str(), strAdd.length(), HTTP_ADDREQ_FLAG_ADD);
                strAdd = "-----------------------------11020459624021--";
                bSend = ::HttpAddRequestHeaders(hRequest, strAdd.c_str(), strAdd.length(), HTTP_ADDREQ_FLAG_ADD);
            
            
                bSend = ::HttpSendRequest(hRequest, NULL, 0, (void*)strAdd.c_str(), strAdd.length());
            
                CString strEdit="";
                if(!bSend)
                {
                    InternetCloseHandle(hRequest);
                    InternetCloseHandle(hConnect);
                    InternetCloseHandle(hInetSession);
                    AfxMessageBox("---1");
                    return;
                }
                else
                {
                    // читаем данные
                    char  szData[204800];
                    DWORD dwBytesRead;
                    BOOL bRead =
                        ::InternetReadFile(
                        hRequest,
                        szData,sizeof(szData)-1,
                        &dwBytesRead);
                    szData[dwBytesRead] = 0;
                    if(bRead) {
                        strEdit = szData;
                        UpdateData(false);
                    }
                    else {
                        strEdit = "Нет данных";
                        UpdateData(false);
                                        }
                }
            
                AfxMessageBox(strEdit);
            
                unsigned long ulSource = 0;
            
                InternetSetFilePointer(hRequest, 0, NULL, FILE_BEGIN, NULL);
                InternetReadFile(hRequest, (LPVOID)&cBuf, 200000, &dwRead);
                InternetCloseHandle(hRequest);

      т.е. lpOptional кладу следующий текст:
      Цитата
      Content-Type: multipart/form-data; boundary=---------------------------11020459624021
      Content-Length: 831083
      \\
      -----------------------------11020459624021
      Content-Disposition: form-data; name="pic1"; filename="d:\MyVC++\~BackupOK\1.JPG"
      Content-Type: image/jpeg
      ....................
      -----------------------------11020459624021--

      А в ответ получаю сообщение:
      Цитата
      {"error_msg":"one.image.server.upload.ContentUploadServerException: NO_IMAGE","error_code":"505","error_data":"NO_IMAGE"}
      Расшифровка ошибок говорит, что ошибка 505 - В запросе не найдено изображение.
      Гугл снова говорит, что это классическая ошибка нубов и всё давно разжевано, мол пользуйте гугл. Впал в рекурсию, выпал по таймауту и пришел просить помощи у наших гуру.

      С уважением!
      Сообщение отредактировано: Lerik -
        Так, косячок обнаружен.
        При помощи сниффера смог посмотреть на работающий запрос и выяснил, что вместо строки "...................." надо передавать собственно содержимое файла в бинарном виде.
        Считать файл в бинарном виде особых проблем не составляет, но как его засунуть в функцию HttpAddRequestHeaders(...)? Ведь для JPG бинарное и текстовое представление отличаются.
        Сообщение отредактировано: Lerik -
          Всем читающим мои мысли вслух - спасибо, получилось.

          Оказалось, что в HttpAddRequestHeaders(...) надо передавать только "Content-Type: multipart/form-data; boundary=---------------------------11020459624021"
          Все остальное надо собрать в единый char* и передать в HttpSendRequest(...).
          Показалось, что проще будет сделать через CMemFile.
          ExpandedWrap disabled
                std::string strTmp="";
                strTmp+="-----------------------------11020459624021";
                strTmp+="\r\n";
                strTmp+="Content-Disposition: form-data; name=\"pic1\"; filename=\"1.JPG\"";
                strTmp+="\r\n";
                strTmp+="Content-Type: image/pjpeg";
                strTmp+="\r\n";
                strTmp+="\r\n";
                mf.Write(strTmp.c_str(), strTmp.length());
             
                CFile fileJPG("d:\\MyVC++\\~BackupOK\\1.JPG", CFile::modeRead|CFile::typeBinary);
                
                char* strFile = new char[fileJPG.GetLength()];  
                fileJPG.Read(strFile,fileJPG.GetLength());
                mf.Write(strFile,fileJPG.GetLength());
                delete[] strFile;
             
                strTmp="";
                strTmp+="\r\n";
                strTmp+="-----------------------------11020459624021--";
                mf.Write(strTmp.c_str(), strTmp.length());
             
                mf.SeekToBegin();
             
                char* strBuff = new char[mf.GetLength()];  
                mf.Read(strBuff,mf.GetLength());
             
                bSend = ::HttpSendRequest(hRequest, NULL, 0, strBuff, mf.GetLength());
             
                delete[] strBuff;
            Цитата Lerik @
            ссылка "Вопрос решен" означает, что он как раз НЕ решен...

            Да нет, там знака вопроса нет.
            Цитата Lerik @
            Слушай, а в списке тем ты у этой темы зеленую галочку видишь?

            Нет, никакой галочки я не вижу.

            Цитата Lerik @
            А у меня сейчас как раз не решен стал...

            Странно. Только что было заявлено что все решилось:
            Цитата Lerik @
            спасибо, получилось.

            И по сути:
            То, о чем вы пишите, не сетевое программирование - а программирование приложений для сети - со всеми вытекающими для этого раздела форума последствиями.
            Ну впрочем может кто и откликнется...
            Поэтому и не переношу в более соответствующий заявленной проблеме раздел. :)
            Сообщение отредактировано: Oleg2004 -
              Oleg2004, в общем я снова ставлю отметку, что вопрос решен, т.к. он действительно уже решен.
              Что касается нужного раздела, я долго выбирал в какой раздел написать, но почему-то решил, что мне сюда. А что за раздел "программирование приложений для сети"? Где это?
              Тему можно двинуть по усмотрению модератора, я нисколько не против.
              И потереть бы этот флейм.
              Спасибо.
                Цитата Lerik @
                А что за раздел "программирование приложений для сети"? Где это?

                Вы уже упоминали один из таких разделов - это WEB-программирование. :)
                А чисто "сетевым программированием" является программирование на базе интерфейса сокетов, и это программирование выполняется в рамках С/С++. На других языках такое программирование в настоящее время отсутствует.
                PS
                Тему почистил... :)
                Сообщение отредактировано: Oleg2004 -
                  Цитата Oleg2004 @
                  Вы уже упоминали один из таких разделов - это WEB-программирование.
                  :) Правда там мне сказали, что там я тоже не по адресу. :lol:
                  Спасибо!
                    Ну да, я посмотрел - вы запостили в раздел PHP, а это реально не туда :)
                    Впрочем поискал по форуму - таких тем мало, и реально постили кто куда... :)
                    Вообще то такого более соответствующего раздела увы на форуме нет. Разве что WWW Masters.
                      Oleg2004
                      нормальный раздел и нормальная тема. Соответствующая.
                      Наиболее эффективно (может быть с моей субъективной точки зрения) формировать http запросы в целом (GET, POST, ....) - libcurl.
                      Может кому пригодится
                      https://curl.haxx.se/libcurl/c/http-post.html
                        Цитата nemez @
                        нормальный раздел и нормальная тема. Соответствующая.

                        Согласитесь, правильное формирование запросов протокола HTTP - не имеет отношения к сетевому программированию (т.е. программирование приложений на базе интерфейса сокетов).
                        И по моему пониманию, HTTP-протокол скорее относится к WEB-программированию, как и например реализация стандарта CGI - расширение WEB-сервера можно написать на любом языке, в том числе и на С/C++.
                        Сетевое программирование лишь снабжает пользователя средствами доставки текстового контента, и не имеет прямого отношения к его содержимому.
                        К сожалению соответствующего раздела у нас на форуме нет, и люди постят и в раздел Дельфи, и в PHP, и в сишные разделы - это показывает поиск по форуму.
                        Поэтому я и не возражал в размещении этой темы в данном разделе. :)
                        По сути, использование WININET оправдывает такой подход, потому что это ведь Си. :)
                        Но - проблема решена, и автор преуспел в решении своей проблемы.
                          Цитата Oleg2004 @
                          Согласитесь, правильное формирование запросов протокола HTTP - не имеет отношения к сетевому программированию (т.е. программирование приложений на базе интерфейса сокетов).



                          имеет, и самое непосредственное.
                          Мы здесь работаем с разного уровня сетевыми протоколами и честно, абсолютно по боку, на каком уровне модели OSI мы находимся. Или переименуйте раздел с "сетевого программирования" в "реализацию протоколов транспортного уровня" - и будем наслаждаться обсуждением TCP сокетов =) И только!
                          И честно, нам приходится, к примеру, работать через прокси. Порой реализовывать на С++ (а здесь раздел с++) протоколы уже более высокого уровня - прикладного, а это тот же HTTP.
                          И все это - темы сетевого программирования. Также, как и особенности реализации разных (!) сетевых протоколов на различных (!) платформах
                          Все это суть обширного раздела Сетевого Программирования
                            Цитата nemez @
                            Или переименуйте раздел с "сетевого программирования" в "реализацию протоколов транспортного уровня" - и будем наслаждаться обсуждением TCP сокетов =) И только!

                            Реализацией протоколов транспортного уровня стека TCP/IP занимаются разработчики операционных систем, однако.
                            Так же как к примеру TDI-интерфейс винды - там тоже сокеты, но мы ими не занимаемся - этот интерфейс как и заменивший его WSK - это приложения уровня ядра, и их тоже пишут в Редмонде.
                            Ваша точка зрения расплывчата.
                            Например написать броузер - это сетевое программирование?
                            Неа, там сетевого только два модуля - TCP-клиент и UDP-клиент.
                            А вот интерпретаторы - HTML, JavaScript, VBScript, PHP и др. - это теория компиляции.
                            Сетевики о ней ни ухом...
                            Так что я пока что с вами не согласен.
                            Есть - сетевое программирование - а есть программирование ДЛЯ использования в сети.
                            Хорошо конечно, когда один и тот же прогер знает все. Тогда он и получает неплохо.
                            Сообщение отредактировано: Oleg2004 -
                              ТС смотри исходники

                              [C++] azHTTP
                              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                              0 пользователей:


                              Рейтинг@Mail.ru
                              [ Script execution time: 0,0395 ]   [ 17 queries used ]   [ Generated: 20.04.24, 04:54 GMT ]