专栏首页Windows开发基于libcurl进行HTTP请求

基于libcurl进行HTTP请求

系统学习Windows客户端开发


互联网时代,单机客户端应用几乎不存在,许多服务存在云端,客户端通过HTTP(Restful API)访问云端服务,所以HTTP请求基础能力是客户端必备的。

HTTP请求实现可以基于Windows SDK提供的WinHTTP, WinHTTP在WinXP下不支持https请求。本文介绍内容是基于libcurl库实现,libcurl库免费、开源、跨平台,支持HTTP、FTP等许多协议,被许多应用使用如:Google Chrome、Google Youtube、Apple iTunes。

接下来,以curl-7.56.3,Visual Studio 2013,Win7系统下介绍libcurl的编译。

第一,libcurl官网下载curl-7.65.3,解压到$(rootpath)\curl-7.65.3,$(rootpath)指解压的根目录。

第二,如果不需要支持https协议,此步骤跳过。下载openssl-1.0.2t-vc14-x86,地址:https://windows.php.net/downloads/php-sdk/deps/。创建$(rootpath)\deps目录,将openssl的lib、include、bin拷贝到$(rootpath)\deps目录下。

第三,启动命令行,执行命令 cd $(rootpath)\curl-7.65.3\winbuild,执行命令 $(VSInstallPath)\VC\vcvarsall.bat,$(VSInstallPath)指Visual Studio安装路径。

第四,编译,执行命令 nmake /f Makefile.vc mode=dll VC=12 WITH_SSL=dll GEN_PDB=yes DEBUG=no MACHINE=x86,其中mode参数指定编译成动态库(dll)还是静态库(static), 如果不需要支持https要去除WITH_SSL=dll,DEBUG参数指定Debug版还是Release版。

libcurl有两种使用方法 Easy 和 Multi。Easy是同步、高效、快速简单的使用方式。Multi是异步的使用方式,一个线程同时可以进行多个网络传输。本文先介绍Easy使用方式。

Easy使用流程如下图所示:

第一,调curl_global_init()接口进行全局初始化,一个进程只需调用一次。如果一次都未调用,curl_easy_init()接口内部会自动调curl_global_init(),因为curl_easy_init()并不是多线程安全,如果两个线程同时调用curl_easy_init(),会概率出现一个线程在没有全局初始化下就进行网络传输导致崩溃,于是强烈建议显示调用curl_global_init()进行libcurl库进行全局初始化。

第二,调curl_easy_init()接口分配一个网络传输对象,因为libcurl是以C语言接口形式提供,所以后续调用的接口都需要提供该接口返回的句柄。

第三,调curl_easy_setopt()设置网络传输对象参数,该接口的第2个参数指定设置的参数类型,第3个参数是一个指针,其值依第2个参数不同而不同(详见libcurl帮助文档),下面主要列举http请求常用的设置项,具体使用参考后面的demo代码:

1)CURLOPT_VERBOSE,设置值为1启用调试输出,此时要设置CURLOPT_DEBUGFUNCTION 调试输出函数,排查问题时使用。

2)CURLOPT_URL,设置URL地址

3)CURLOPT_PUT,设置HTTP请求方法为PUT,CURLOPT_POST设置HTTP请求方法为POST,要设置HTTP请求方法为DELETE或PATCH,就得用CURLOPT_CUSTOMREQUEST。

4)CURLOPT_POSTFIELDS,设置HTTP请求body内容,CURLOPT_POSTFIELDSIZE设置body大小,如果body内容是以\0结尾,可以不指定body大小。

5)CURLOPT_HTTPHEADER,设置HTTP头部,HTTP头部是用curl_slist结构的链表,curl_slist_append()添加HTTP头部,可以调多次添加多个头部,curl_slist_free_all()释放curl_slis对象。

6)CURLOPT_WRITEFUNCTION,设置HTTP请求body的数据输出函数,同时可以指定CURLOPT_WRITEDATA作为输出函数的user_data,libcurl会透传user_data。

7)CURLOPT_TIMEOUT_MS设置网络请求总超时值,CURLOPT_CONNECTTIMEOUT_MS设置网络socket连接超时值。

8)CURLOPT_SSL_VERIFYPEER 设置0时不校验服务端,HTTPS请求时如果本地没有服务端证书,需要设置为0。

第四,调curl_easy_perform()接口执行网络请求,返回值CURLE_OK表示成功,只有成功时获取响应码和响应body才有效。

第五,调curl_easy_getinfo()接口获取网络请求响应信息,它类似于curl_easy_setopt()接口,第2个参数指定获取项,第3个参数依第2个参数不同而不同,比较常用的是CURLINFO_RESPONSE_CODE,获取状态码。

第六,调curl_easy_cleanup()接口释放资源

第七,调curl_global_cleanup()接口释放全局资源

下面的demo代码介绍如何使用libcurl库进行HTTP GET和POST请求。

#include <stdio.h>
#include <curl/curl.h>
#include <string>

size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
    ((std::string*)userdata)->append(ptr, nmemb);
    return nmemb;
}

int main(void)
{
    curl_global_init(CURL_GLOBAL_DEFAULT);
    CURL* curl = curl_easy_init();
    if (curl) 
    {        
        curl_easy_setopt(curl, CURLOPT_URL, "https://www.baidu.com");

        // no certificate, not verify server certificate
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);

        std::string response_data;
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
        CURLcode res = curl_easy_perform(curl);
        if (res != CURLE_OK)
        {
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                curl_easy_strerror(res));
        }
        else
        {
            long response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
            printf("response code %d \n", response_code);
            printf("response data : \n ");
            printf(response_data.c_str());
        }

        curl_easy_cleanup(curl);
    }

    curl_global_cleanup();
    return 0;
}
#include <stdio.h>
#include <curl/curl.h>
#include <string>

size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
{
    ((std::string*)userdata)->append(ptr, nmemb);
    return nmemb;
}

int main(int argc, void* argv)
{
    curl_global_init(CURL_GLOBAL_DEFAULT);
    CURL* curl = curl_easy_init();
    if (curl)
    {
        // set url
        curl_easy_setopt(curl, CURLOPT_URL, "https://jsonplaceholder.typicode.com/posts");

        // no certificate, not verify server certificate
        curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);

        // set http method
        curl_easy_setopt(curl, CURLOPT_POST, 1);

        // set header
        struct curl_slist * slist = nullptr;
        slist = curl_slist_append(slist, "Content-Type : application/json");
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, slist);

        // set body
        std::string body = "{\
            \"title\":\"libcurl post title\",\
            \"body\" : \"libcurl post body\",\
            \"userId\" : 1}";
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body.c_str());

        // set response callback to read response
        std::string response_data;        
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response_data);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
        CURLcode res = curl_easy_perform(curl);
        if (res != CURLE_OK)
        {
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                curl_easy_strerror(res));
        }
        else
        {
            // get response code
            long response_code;
            curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response_code);
            printf("response code %d \n", response_code);
            printf("response data : \n ");
            printf(response_data.c_str());
        }

        curl_slist_free_all(slist);
        curl_easy_cleanup(curl);
    }

    curl_global_cleanup();
    return 0;
}

本文分享自微信公众号 - Windows开发(gh_5216ec78fc5b),作者:kinglon

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-12-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 如何保证static变量只初始化一次

    static变量分为两种情况:第一种是初始化为常量,在编译的时候就可以确定初始值;第二种是初始值在运行的时候才能确定,比如赋值为函数的返回值或 某个类的实例。

    gaigai
  • 链接时无法解析符号checklist

    主要原因包括四类:函数声明与实现的原型不一致、函数声明与实现的作用域不同、函数声明但没有实现、使用DLL接口不当。

    gaigai
  • 如何隔离第三方组件的崩溃

    在引入第三方组件的时候,如果其稳定性不够偶尔会崩溃,如何将它进行隔离使得其崩溃不会影响主程序崩溃呢?

    gaigai
  • Http Post 快速使用

    点击上方蓝字可直接关注!方便下次阅读。如果对你有帮助,麻烦点个在看或点个赞,感谢~

    用户5908113
  • curl使用小记(二)——远程下载一张图片

    在之前的文章《curl使用小记(一)》中论述了命令行工具curl的基本使用。除此之外,curl还提供了能够直接供程序调用的模块库接口libcurl。这里就通过一...

    charlee44
  • 搭建采集金山词霸每日一句接口

    查指定时间:http://sentence.iciba.com/index.php?c=dailysentence&m=getdetail&title=2018...

    周俊辉
  • PHP网络技术(三)——CURL实现跨服务取接口功能

    PHP网络技术(三)——CURL实现跨服务取接口功能 (原创内容,转载请注明来源,谢谢) PHP的curl类库,可以实现远程访问、页面抓取、表...

    用户1327360
  • Linux常用命令08 - curl

    curl 是一个命令行实用程序,用于将数据从服务器或传输到服务器,该服务器设计用于在没有用户交互的情况下工作。 使用 curl,您可以使用支持的协议(包括 HT...

    叉叉敌
  • PHP 问题合集

    SSL certificate problem, verify that the CA cert is OK

    WindWant
  • php使用CURL模拟POST请求函数

    本文为仙士可原创文章,转载无需和我联系,但请注明来自仙士可博客www.php20.cn

    仙士可

扫码关注云+社区

领取腾讯云代金券