wpr*_*ins 1 c++ opencv libcurl
我正在向Cloudinary API发送POST多部分,以上传我使用openCV捕获和缓冲的图像.Cloudinary正在给我一个HTTP 400.我已经测试了使用chrome应用程序上传图像PostMan并且可以正常工作,因此我的POST请求中必定存在错误或者我如何缓冲数据有些错误.
下面是他们如何描述对API的调用:http: //cloudinary.com/documentation/upload_images#uploading_with_a_direct_call_to_the_api
我已经在这几天了,任何帮助将不胜感激.一旦弄明白,我将把这个代码提交给Cloudinary,这样摆弄C/C++的其他用户就可以轻松上传到他们的平台,而不会感到痛苦.
//Clone frame and encode into buffer as JPEG
cv::Mat hand_roi = frame.clone();
std::vector<unsigned char> imgBuffer;
imencode(".jpg", hand_roi, imgBuffer);
//Buffer to String with pointer/length
std::string imgStrBuff = std::string(imgBuffer.begin(), imgBuffer.end());
char *imgBuffPtr = (char *)&imgStrBuff;
long imgBuffLength = static_cast<long>(imgStrBuff.size());
//Unix time in (s)
std::time_t t = std::time(0);
std::string unixTime = std::to_string(t);
//API_Secret:
std::string APISecret = "XXXXXXXXXXXXXXXXXXXXX";
//Create SHA1 signature required by cloudinary
std::string hashString = "timestamp=" + unixTime + APISecret;
std::string authSig = sha1(hashString);
//POST URL
std::string url = "https://api.cloudinary.com/v1_1/xxxxxxxxxxx/image/upload";
/*-----CURL SETUP-----*/
//Set headers as null
struct curl_slist *headers = NULL;
struct curl_httppost *formpost = NULL;
struct curl_httppost *lastptr = NULL;
//Data type
curl_slist_append(headers, "Content-Type: multipart/form-data");
curl_global_init(CURL_GLOBAL_ALL);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "api_key",
CURLFORM_COPYCONTENTS, "xxxAPIKeyxxx",
CURLFORM_END);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "timestamp",
CURLFORM_COPYCONTENTS, unixT.c_str(),
CURLFORM_END);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "signature",
CURLFORM_COPYCONTENTS, authSig.c_str(),
CURLFORM_END);
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "file",
CURLFORM_BUFFER, "random_img_name.jpg",
CURLFORM_BUFFERPTR, imgBuffPtr,
CURLFORM_BUFFERLENGTH, imgBuffLength,
CURLFORM_END);
//init easy_curl
CURL* curl = curl_easy_init();
if(!curl)
return false;
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
res = curl_easy_perform(curl);
Run Code Online (Sandbox Code Playgroud)
我已经阅读了基本上所有的libcurl文档,我只是无法弄清楚为什么这些请求被拒绝.
你的代码有几个问题,我将逐一解决它们,从最关键的一个开始,导致操作实际失败.
问题出在这一部分:
std::string imgStrBuff = std::string(imgBuffer.begin(), imgBuffer.end());
char *imgBuffPtr = (char *)&imgStrBuff;
long imgBuffLength = static_cast<long>(imgStrBuff.size());
Run Code Online (Sandbox Code Playgroud)
这样做:它填充imgBuffer到C++字符串imgStrBuff,然后将指向字符串描述符的指针误解为指向实际数据的指针并将其存储imgBuffPtr.(正确的)数据长度存储在imgBuffLength.
所以,更进一步,你要求CURL imgBuffLength从地址开始从内存中读取字节imgBuffPtr...你很幸运你的程序不只是崩溃,因为它现在将读取字符串描述符和任何垃圾偶然位于内存中就在它之后,而不是实际的数据!
我想你真正想要做的是char *imgBuffPtr = imgStrBuff.c_str();,但是有一种更好的方法,中间没有任何字符串:
char *imgBuffPtr = &imgBuffer[0];
long imgBuffLength = imgBuffer.size();
Run Code Online (Sandbox Code Playgroud)
该标准要求a std::vector将其数据存储在连续内存中,因此只需使用指向其第一个元素的指针即可.
curl_global_init不是在合适的时间打电话curl_global_init应该在任何其他CURL函数之前调用,但是你只需要调用一次.所以在这个特定的代码中,它必须超越调用curl_slist_append,但实际上你只需要在程序的启动例程中使用它.
curl_slist_append来headers这行无效(除了创建列表并泄漏它):
curl_slist_append(headers, "Content-Type: multipart/form-data");
Run Code Online (Sandbox Code Playgroud)
这是因为您必须将其返回值分配回变量headers,如下所示:
headers = curl_slist_append(headers, "Content-Type: multipart/form-data");
Run Code Online (Sandbox Code Playgroud)
Content-Type标题是不必要的正如评论者Daniel Stenberg已经指出的那样,没有必要将你的内容类型设置为标题CURL_HTTPPOST,因为它已经为你做了 - 实际上,它必须是因为它必须定义一个多部分边界.
以下内容仅适用于您的代码中尚未安装此内容的情况:
您正在创建一个简单的会话变量curl,一个curl_slist headers(虽然这已被#4淘汰)和一个curl_httppost结构formpost.
完成后,您必须使用以下代码再次释放它们:
curl_easy_cleanup(curl);
curl_formfree(formpost);
curl_slist_free_all(headers);
Run Code Online (Sandbox Code Playgroud)
下次遇到这样的问题时,您应该明确地做两件事:
正如评论者Remy Lebeau已经建议的那样,使用Wireshark或SmartSniff等数据包嗅探器或Fiddler等分析代理来查看实际发送或接收的内容.您可能需要更改协议以http://使其工作(之后再将其更改!),否则您将只看到加密的SSL数据.通过这种方式,您可以了解实际情况以及问题所在.然后,您还可以比较两个版本的数据,一个可以工作(例如从命令行或浏览器),哪个不工作.
检查从API返回的实际响应正文.您可能需要curl_easy_setopt(curl, CURLOPT_FAILONERROR, 0);这样,即使状态代码> = 400,您也可以获得正文,并且数据写回调(请查看此示例).如果你这样做了,你会注意到API发送的错误{"error":{"message":"Invalid image file"}}已经给你一个线索了.
| 归档时间: |
|
| 查看次数: |
4388 次 |
| 最近记录: |