【问题标题】:Sending a file via multipart using libcurl in C++在 C++ 中使用 libcurl 通过 multipart 发送文件
【发布时间】:2021-11-10 18:57:48
【问题描述】:

我正在尝试使用 libcurl 和 C++ 通过 POST 请求将文件上传到远程位置。但是,我认为我做错了什么,因为我被告知文件没有到达另一端。

我正在使用以下代码:

#include "curl/curl.h"

using namespace std;

size_t WriteCallback(void * buffer, size_t size, size_t count, void * user)
{
  ((string *) user)->append((char *) buffer, 0, size * count);
  return size * count;
}

int main()
{

  curl_global_init(CURL_GLOBAL_ALL);

  CURL * Curl;
  CURLCode res;
  Curl = curl_easy_init();
  curl_easy_setopt(Curl, CURLOPT_FAILONERROR, 0);
  curl_easy_setopt(Curl, CURLOPT_VERBOSE, 1L);

  struct curl_httppost * formpost = NULL;
  struct curl_httppost * lastptr = NULL;
  struct curl_slist * headerlist = NULL;
  static const char buf[] = "Expect:";

  ImageName = "myimage.jpg"
  ImageNameWithPath = "/this/location/right/here/" + ImageName;

  curl_formadd(& formpost,
               & lastptr,
               CURLFORM_COPYNAME, ImageName.c_str();
               CURLFORM_FILE, ImageNameWithPath.c_str();
               CURLFORM_CONTENTTYPE, "image/jpeg (binary)";
               CURLFORM_END);

  curl_formadd(& formpost,
               & lastptr,
               CURLFORM_COPYNAME, ImageName.c_str();
               CURLFORM_COPYCONTENTS, ImageNameWithPath.c_str();
               CURLFORM_CONTENTTYPE, "image/jpeg (binary)";
               CURLFORM_END);

  headerlist = curl_slist_append(headerlist, buf);

  string MessageBodyLine1 = "Content-Disposition: form-data; name=\"file\"; filename\"" + ImageName + "\"";
  headerlist = curl_slist_append(headerlist, MessageBodyLine1.c_str());

  string Url = https://www.example.com/ // There is a real URL here
  curl_easy_setopt(Curl, CURLOPT_URL, Ulr.c_str());

  curl_easy_setopt(Curl, CURLOPT_HTTPHEADER, headerlist);
  curl_easy_setopt(Curl, CURLOPT_HTTPPOST, formpost);

  string Reponse;
  curl_easy_setopt(Curl, CURLOPT_WRITEFUNCTION, WriteCallback);
  curl_easy_setopt(Curl, CURLOPT_WRITEDATA, & Response);


  res = curl_easy_perform(Curl);
  curl_easy_cleanup(Curl);
  curl_formfree(formpost);
  curl_slist_free_all(headerlist);

  curl_global_cleanup();

  return 0;

我实际上希望输出在某处看起来像这样

POST URL HTTP/1.1
Content-Type: multipart/form-data; boundary=----BoundaryString

----BoundaryString
Content-Disposition: form-data; name="file"; filename="myfile.jpg"
Content-Type: image/jpeg (binary)

相反,我得到了这个:

* Trying IP
* Connected to IP port PORT (#0)
POST URL HTTP/1.1
Host: IP
Accept: IP:PORT
Content-Disposition: form-data; name="file"; filename="myfile.jpg"
Content-Length: totalsize

Content-Type: multipart/form-data; boundary=----BoundaryString

< HTTP/1.1 200 OK
[...]

现在它说好的,但我知道图像没有到达另一边。此外,我的Response 字符串也是空的,但它应该包含一个 JSON 字符串。

我做错了什么?不幸的是,我坚持使用旧的 libcurl 版本,因此无法使用 curl 7.55 中可用的 mime 格式。

【问题讨论】:

  • 你确定你得到了你发布的输出吗?标题中的空行?代码"filename\"" + 不能产生filename="myfile.jpg"
  • 我比较积极。实际线路是string MessageBodyLine1 = "Content-Disposition: form-data; name=\"file\"; filename\"" + ImageName + "\"";。抱歉,由于某种原因,那里有一个换行符。我之前定义了图像名称,但在工作软件中,这实际上是一个将图像名称作为参数获取的函数。我还开始使用link 观察网络设备,我可以肯定地看到,定期传输大约 500000 到 700000 个字节,这是我要发送的图像的大小。所以我假设应用程序正在尝试发送它但失败了。
  • 看例子curl.se/libcurl/c/postit2.html如何正确处理多部分内容。

标签: c++ curl post multipartform-data libcurl


【解决方案1】:

请勿在 HTTP 请求的 headerlist 中添加 Content-Disposition 请求标头,它不属于那里。相反,它属于每个 MIME 部分(即,您应该使用CURLFORM_COPYNAME, "file"CURLFORM_FILE, ImageName.c_str())。我希望curl_formadd() 为您处理Content-Disposition,您不需要手动创建它。

另外,image/jpeg (binary) 不是有效的Content-Type 值,它必须是image/jpeg

您为什么要为同一个文件调用两次curl_formadd(),一次调用CURLFORM_FILE,另一次调用CURLFORM_COPYCONTENTS?特别是因为您对CURLFORM_COPYCONTENTS 的输入是错误的(它需要一个指向实际数据的指针,而不是指向文件名字符串的指针)。在这种情况下,您应该只使用 CURLFORM_FILE

试试这个:

#include "curl/curl.h"
#include <string>
using namespace std;

size_t WriteCallback(void * buffer, size_t size, size_t count, void * user)
{
  size_t numBytes = size * count;
  static_cast<string*>(user)->append(static_cast<char*>(buffer), 0, numBytes);
  return numBytes;
}

int main()
{
  curl_global_init(CURL_GLOBAL_ALL);

  CURL *Curl = curl_easy_init();
  if (!Curl)
    return -1;

  curl_easy_setopt(Curl, CURLOPT_FAILONERROR, 0);
  curl_easy_setopt(Curl, CURLOPT_VERBOSE, 1L);

  curl_httppost *formpost = NULL;
  curl_httppost *lastptr = NULL;

  string ImageName = "myimage.jpg";
  string ImageNameWithPath = "/this/location/right/here/" + ImageName;

  curl_formadd(&formpost,
               &lastptr,
               CURLFORM_COPYNAME, "file",
               CURLFORM_FILE, ImageNameWithPath.c_str(),
               CURLFORM_CONTENTTYPE, "image/jpeg",
               CURLFORM_END);

  curl_slist *headerlist = curl_slist_append(NULL, "Expect:");

  string Url = https://www.example.com/ // There is a real URL here
  curl_easy_setopt(Curl, CURLOPT_URL, Url.c_str());

  curl_easy_setopt(Curl, CURLOPT_HTTPHEADER, headerlist);
  curl_easy_setopt(Curl, CURLOPT_HTTPPOST, formpost);

  string Reponse;
  curl_easy_setopt(Curl, CURLOPT_WRITEFUNCTION, WriteCallback);
  curl_easy_setopt(Curl, CURLOPT_WRITEDATA, &Response);

  CURLCode res = curl_easy_perform(Curl);

  curl_easy_cleanup(Curl);
  curl_formfree(formpost);
  curl_slist_free_all(headerlist);

  curl_global_cleanup();

  return 0;
}

【讨论】:

  • 非常感谢,这解决了我的问题!我不知道如何包含 Content-Disposition,但现在我学到了一些东西。 :) 我之所以调用它两次是因为我在几个教程中都看到过这个,但很可能我只是误解了意图。
猜你喜欢
  • 1970-01-01
  • 2020-02-05
  • 2012-04-27
  • 1970-01-01
  • 1970-01-01
  • 2018-06-16
  • 2021-02-21
  • 2019-08-27
  • 1970-01-01
相关资源
最近更新 更多