Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.133.149.168] |
|
Сообщ.
#1
,
|
|
|
Доброго времени суток!
Не сочтите за наглость: создал тему в разделе "Web технологии", но попробую спросить и тут. Пытаюсь залить фото на одноклассники через их API. Как показал гугл, я как и основная масса споткнулся на втором шаге: загрузка фотографий через HTTP POST. Если верить их документации, то мне надо отправить POST-запрос: 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). 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-- А в ответ получаю сообщение: Цитата Расшифровка ошибок говорит, что ошибка 505 - В запросе не найдено изображение.{"error_msg":"one.image.server.upload.ContentUploadServerException: NO_IMAGE","error_code":"505","error_data":"NO_IMAGE"} Гугл снова говорит, что это классическая ошибка нубов и всё давно разжевано, мол пользуйте гугл. Впал в рекурсию, выпал по таймауту и пришел просить помощи у наших гуру. С уважением! |
Сообщ.
#2
,
|
|
|
Так, косячок обнаружен.
При помощи сниффера смог посмотреть на работающий запрос и выяснил, что вместо строки "...................." надо передавать собственно содержимое файла в бинарном виде. Считать файл в бинарном виде особых проблем не составляет, но как его засунуть в функцию HttpAddRequestHeaders(...)? Ведь для JPG бинарное и текстовое представление отличаются. |
Сообщ.
#3
,
|
|
|
Всем читающим мои мысли вслух - спасибо, получилось.
Оказалось, что в HttpAddRequestHeaders(...) надо передавать только "Content-Type: multipart/form-data; boundary=---------------------------11020459624021" Все остальное надо собрать в единый char* и передать в HttpSendRequest(...). Показалось, что проще будет сделать через CMemFile. 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; |
Сообщ.
#4
,
|
|
|
Да нет, там знака вопроса нет. Нет, никакой галочки я не вижу. Странно. Только что было заявлено что все решилось: Цитата Lerik @ спасибо, получилось. И по сути: То, о чем вы пишите, не сетевое программирование - а программирование приложений для сети - со всеми вытекающими для этого раздела форума последствиями. Ну впрочем может кто и откликнется... Поэтому и не переношу в более соответствующий заявленной проблеме раздел. |
Сообщ.
#5
,
|
|
|
Oleg2004, в общем я снова ставлю отметку, что вопрос решен, т.к. он действительно уже решен.
Что касается нужного раздела, я долго выбирал в какой раздел написать, но почему-то решил, что мне сюда. А что за раздел "программирование приложений для сети"? Где это? Тему можно двинуть по усмотрению модератора, я нисколько не против. И потереть бы этот флейм. Спасибо. |
Сообщ.
#6
,
|
|
|
Цитата Lerik @ А что за раздел "программирование приложений для сети"? Где это? Вы уже упоминали один из таких разделов - это WEB-программирование. А чисто "сетевым программированием" является программирование на базе интерфейса сокетов, и это программирование выполняется в рамках С/С++. На других языках такое программирование в настоящее время отсутствует. PS Тему почистил... |
Сообщ.
#7
,
|
|
|
Цитата Oleg2004 @ Правда там мне сказали, что там я тоже не по адресу. Вы уже упоминали один из таких разделов - это WEB-программирование. Спасибо! |
Сообщ.
#8
,
|
|
|
Ну да, я посмотрел - вы запостили в раздел PHP, а это реально не туда
Впрочем поискал по форуму - таких тем мало, и реально постили кто куда... Вообще то такого более соответствующего раздела увы на форуме нет. Разве что WWW Masters. |
Сообщ.
#9
,
|
|
|
Oleg2004
нормальный раздел и нормальная тема. Соответствующая. Наиболее эффективно (может быть с моей субъективной точки зрения) формировать http запросы в целом (GET, POST, ....) - libcurl. Может кому пригодится https://curl.haxx.se/libcurl/c/http-post.html |
Сообщ.
#10
,
|
|
|
Цитата nemez @ нормальный раздел и нормальная тема. Соответствующая. Согласитесь, правильное формирование запросов протокола HTTP - не имеет отношения к сетевому программированию (т.е. программирование приложений на базе интерфейса сокетов). И по моему пониманию, HTTP-протокол скорее относится к WEB-программированию, как и например реализация стандарта CGI - расширение WEB-сервера можно написать на любом языке, в том числе и на С/C++. Сетевое программирование лишь снабжает пользователя средствами доставки текстового контента, и не имеет прямого отношения к его содержимому. К сожалению соответствующего раздела у нас на форуме нет, и люди постят и в раздел Дельфи, и в PHP, и в сишные разделы - это показывает поиск по форуму. Поэтому я и не возражал в размещении этой темы в данном разделе. По сути, использование WININET оправдывает такой подход, потому что это ведь Си. Но - проблема решена, и автор преуспел в решении своей проблемы. |
Сообщ.
#11
,
|
|
|
Цитата Oleg2004 @ Согласитесь, правильное формирование запросов протокола HTTP - не имеет отношения к сетевому программированию (т.е. программирование приложений на базе интерфейса сокетов). имеет, и самое непосредственное. Мы здесь работаем с разного уровня сетевыми протоколами и честно, абсолютно по боку, на каком уровне модели OSI мы находимся. Или переименуйте раздел с "сетевого программирования" в "реализацию протоколов транспортного уровня" - и будем наслаждаться обсуждением TCP сокетов =) И только! И честно, нам приходится, к примеру, работать через прокси. Порой реализовывать на С++ (а здесь раздел с++) протоколы уже более высокого уровня - прикладного, а это тот же HTTP. И все это - темы сетевого программирования. Также, как и особенности реализации разных (!) сетевых протоколов на различных (!) платформах Все это суть обширного раздела Сетевого Программирования |
Сообщ.
#12
,
|
|
|
Цитата nemez @ Или переименуйте раздел с "сетевого программирования" в "реализацию протоколов транспортного уровня" - и будем наслаждаться обсуждением TCP сокетов =) И только! Реализацией протоколов транспортного уровня стека TCP/IP занимаются разработчики операционных систем, однако. Так же как к примеру TDI-интерфейс винды - там тоже сокеты, но мы ими не занимаемся - этот интерфейс как и заменивший его WSK - это приложения уровня ядра, и их тоже пишут в Редмонде. Ваша точка зрения расплывчата. Например написать броузер - это сетевое программирование? Неа, там сетевого только два модуля - TCP-клиент и UDP-клиент. А вот интерпретаторы - HTML, JavaScript, VBScript, PHP и др. - это теория компиляции. Сетевики о ней ни ухом... Так что я пока что с вами не согласен. Есть - сетевое программирование - а есть программирование ДЛЯ использования в сети. Хорошо конечно, когда один и тот же прогер знает все. Тогда он и получает неплохо. |
Сообщ.
#13
,
|
|
|