gpt4 book ai didi

c++ - libcURL POST 分段上传(带缓冲图像)返回 HTTP 400

转载 作者:太空宇宙 更新时间:2023-11-03 21:58:08 26 4
gpt4 key购买 nike

我正在向 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);

我基本上已经阅读了所有 libcurl 文档,但我无法弄清楚为什么这些请求被拒绝了。

最佳答案

您的代码有几个问题,我将一一解决,从导致操作实际失败的最关键的问题开始。

1)您正在为 CURL 提供一个垃圾指针作为文件缓冲区

问题出在这部分:

std::string imgStrBuff = std::string(imgBuffer.begin(), imgBuffer.end());
char *imgBuffPtr = (char *)&imgStrBuff;
long imgBuffLength = static_cast<long>(imgStrBuff.size());

这是做什么的:它填充 imgBuffer转换为 C++ 字符串 imgStrBuff然后 将指向字符串描述符的指针误解为指向实际数据的指针 并将其存储在 imgBuffPtr .数据的(正确)长度存储在 imgBuffLength .

因此,再往下,您要求 CURL 阅读 imgBuffLength从地址 imgBuffPtr 开始的内存中的字节...而且您很幸运,您的程序不仅崩溃了,因为它现在将读取字符串描述符以及紧随其后位于内存中的任何垃圾,而不是实际数据!

我猜你真正想做的是 char *imgBuffPtr = imgStrBuff.c_str(); ,但是有一个更好的方法,中间没有任何字符串:
char *imgBuffPtr = &imgBuffer[0];
long imgBuffLength = imgBuffer.size();

该标准要求 std::vector将其数据存储在连续内存中,因此只需使用指向其第一个元素的指针即可。

2) 您调用 curl_global_init不是在正确的时间
curl_global_init应该在任何其他 CURL 函数之前调用,但您只需要调用一次。所以在这个特定的代码中,它必须超越对 curl_slist_append 的调用。 ,但实际上您只需要在程序的启动例程中的某个地方使用它。

3) 您没有分配 curl_slist_append 的结果至 headers
这一行实际上什么也没做(除了创建一个列表并泄漏它):
curl_slist_append(headers, "Content-Type: multipart/form-data");

这是因为您必须将其返回值分配回变量 headers , 像这样:
headers = curl_slist_append(headers, "Content-Type: multipart/form-data");

4) Content-Type标题是不必要的

正如评论者 Daniel Stenberg 已经指出的那样,没有必要将您的内容类型设置为标题,因为 CURL_HTTPPOST已经为您做到了 - 实际上,它必须这样做,因为它也必须定义一个多部分边界。

5)您正在泄漏数据结构

以下仅适用于您的代码中还没有此功能的情况:

您正在创建一个简单的 session 变量 curl , 一个 curl_slist headers (尽管这已被 #4 废弃)和 curl_httppost结构 formpost .

完成后,您必须使用以下代码再次释放它们:
curl_easy_cleanup(curl);
curl_formfree(formpost);
curl_slist_free_all(headers);

对 future 的一点调试帮助

下次遇到此类问题时,您绝对应该做两件事:
  • 正如评论者 Remy Lebeau 已经建议的那样,使用数据包嗅探器(如 Wireshark 或 SmartSniff)或分析代理(如 Fiddler)来查看实际发送或接收的内容。您可能需要将协议(protocol)更改为 http://不过要让它工作(之后再改回来!),因为否则你只会看到加密的 SSL 数据。通过这种方式,您可以了解真正超出界限的情况以及问题可能出在哪里。然后,您还可以比较两个版本的数据,一个有效(例如,从命令行或浏览器)和您的无效。
  • 检查从 API 返回的实际响应正文。您可能需要curl_easy_setopt(curl, CURLOPT_FAILONERROR, 0);因此,即使状态码 >=400 和数据写入回调(查看 this example),您也会首先获得一个正文。如果您这样做了,您会注意到 API 发送的错误是 {"error":{"message":"Invalid image file"}}这已经给了你一个线索。
  • 关于c++ - libcURL POST 分段上传(带缓冲图像)返回 HTTP 400,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37082651/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com