【问题标题】:Using Libcurl library for file download使用 Libcurl 库进行文件下载
【发布时间】:2020-01-04 10:23:29
【问题描述】:

我正在尝试通过从 Dropbox 或谷歌驱动器中的共享链接下载更新文件来实现自动更新。起初,我使用 Windows API 函数 URLDownloadToFile() 从 Web 下载公共文件。它工作正常,但是当我将它用于云文件时,它没有下载文件。而是得到一个 HTML 文件,当使用浏览器打开时,我可以使用浏览器下载该文件。

所以,我转而使用 Libcurl 库并按照他们的教程进行操作。我总是收到错误

(60) : CURL_PEER_FAILED_VERIFICATION。

我按照https://curl.haxx.se/libcurl/c/url2file.html 的示例进行操作。并尝试获取相同的公共文件,我已经下载了 Windows API,但仍然收到相同的错误。所以我知道这与服务器身份验证或类似问题无关。

这是我同时使用 windows api 和 Libcurl 的下载功能:

static size_t write_data (void *ptr,size_t size,size_t nmemb,void* stream)
{
  size_t written = fwrite (ptr,size,nmemb,(FILE *) stream) ;
  return written ;
} /* write_data */


int DownloadFile ()
{
  static const char FileURL[] = "https://www.pexels.com/photo/618608/download/?search_query=park&tracking_id=6qgsqm6nzau" :
  static char TargetURL[]  = "D:\\Download\\DownloadURL\\Test.jpg" ;
  static char TargetCURL[] = "D:\\Download\\DownloadCURL\\Test.jpg" ;

  // Download the file using windows function into DownloadURL folder
  URLDownloadToFile (nullptr,FileURL[2],TargetURL,0,nullptr) ; // OK

  // Download the file using curl library into DownloadCURL folder
  if (auto curl = curl_easy_init ()) {
      auto fp = fopen (TargetCURL,"wb") ;
      curl_easy_setopt (curl,CURLOPT_URL,FileURL[1]) ;
      curl_easy_setopt (curl,CURLOPT_FAILONERROR,1) ;
      curl_easy_setopt (curl,CURLOPT_WRITEDATA,fp) ;

      /* Perform the request, res will get the return code */
      auto res = curl_easy_perform (curl) ;                     // Always Fail

      fclose (fp) ;
      curl_easy_cleanup (curl) ;
  } /* if (auto curl = curl_easy_init ()) */

  return true ;

} /* Download */

我的系统运行的是 Windows 10 x64。我使用 Visual Studio 2017,Libcurl 修订版 7.67 和 openSSL。

谁能帮我弄清楚缺少什么?

【问题讨论】:

    标签: c++ winapi libcurl


    【解决方案1】:

    您使用的 URL 重定向到此 URL: https://images.pexels.com/photos/618608/pexels-photo-618608.jpeg?cs=srgb&dl=worm-s-eyeview-of-tall-tree-under-a-gray-sky-618608.jpg&fm=jpg 所以你需要在 curl 中启用以下重定向:

    curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // follow redirects

    您还需要提供write_data 函数:

    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);

    还有
    curl_easy_setopt (curl,CURLOPT_URL,FileURL[1]) ;
    应该是
    curl_easy_setopt (curl,CURLOPT_URL,FileURL);

    如果您使用 http 代理,您可能还需要
    curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L);

    #include "curl/curl.h"
    #include <cstdio>
    
    static size_t write_data(void* ptr, size_t size, size_t nmemb, void* stream) {
        size_t written = fwrite(ptr, size, nmemb, static_cast<FILE*>(stream));
        return written;
    } /* write_data */
    
    bool DownloadFile() {
        bool retval = false;
        static const char FileURL[] =
            "https://www.pexels.com/photo/618608/download/"
            "?search_query=park&tracking_id=6qgsqm6nzau";
        static char TargetCURL[] = "D:\\Download\\DownloadCURL\\Test.jpg";
    
        // Download the file using curl library into DownloadCURL folder
        if(CURL* curl = curl_easy_init()) {
            if(FILE* fp = fopen(TargetCURL, "wb")) {
                curl_easy_setopt(curl, CURLOPT_URL, FileURL);
                curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
                curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
                curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
                curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // follow redirects
                curl_easy_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L); // corp. proxies etc.
    
                /* Perform the request, res will get the return code */
                CURLcode res = curl_easy_perform(curl);
                if(!res) retval = true;
    
                fclose(fp);
            }
            curl_easy_cleanup(curl);
        } /* if (auto curl = curl_easy_init ()) */
    
        return retval;
    
    } /* Download */
    
    int main() {
        CURLcode res = curl_global_init(CURL_GLOBAL_ALL);
        if(res) return 1;
        DownloadFile();
        curl_global_cleanup();
    }
    

    【讨论】:

    • 我添加了这一行以及我在原始问题中错过的一行 curl_easy_setopt (curl,CURLOPT_WRITEFUNCTION,write_data) ;但是我仍然收到同样的错误。
    • @makhlouf 上面的完整示例对我有用。你还有同样的问题吗?
    • 是的,我仍然有同样的错误。你真的下载了照片吗?如果是这样,则意味着我构建的库无法正常运行。
    • @makhlouf 是的,我运行了上面的程序,得到了图片。
    【解决方案2】:

    该错误与 TLS 证书颁发者验证有关。您缺少服务器的 CA 证书。默认情况下,Windows OpenSSL 带有一个空的证书存储。在 Windows 上最好编译带有 schannel 支持的 libcurl 而不是 OpenSSL,然后它将使用 Windows 内置的证书存储。

    【讨论】:

    • 我对服务器证书不熟悉。你能给我更多关于渠道支持的信息吗?我在构建 Libcurl 时发现的选项包括:NGHTTP2、MBEDTLS、CARES、ZLIB、SSH2。
    • 我在没有 openSSL 支持的情况下重建了 Libcurl 库。该程序有效,它实际上下载了文件。我搜索了我的 windows 目录,发现它已经包含 schannel.dll 文件。所以我只需要从 Libcurl 中删除 OpenSSL。非常感谢。
    • 是的,schannel 是一个内置的 Windows 组件。如果没有提供其他 SSL 库,Lubcurl 将默认使用它。
    【解决方案3】:

    你需要设置这些选项:

    curl_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0);
    curl_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0); 
    

    也许你可以试试teemo库,它基于libcurl,并且支持多线程下载

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-01-22
      • 1970-01-01
      • 1970-01-01
      • 2010-12-10
      • 1970-01-01
      • 2014-11-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多