1. 程式人生 >實用技巧 >其它 >Libcurl Post Get呼叫方法

Libcurl Post Get呼叫方法


網際網路時代,單機客戶端應用幾乎不存在,許多服務存在雲端,客戶端通過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,解壓到KaTeX parse error: Undefined control sequence: \curl at position 11: (rootpath)\̲c̲u̲r̲l̲-7.65.3,(rootpath)指解壓的根目錄。

第二,如果不需要支援https協議,此步驟跳過。下載openssl-1.0.2t-vc14-x86,地址:https://windows.php.net/downloads/php-sdk/deps/。建立KaTeX parse error: Undefined control sequence: \deps at position 11: (rootpath)\̲d̲e̲p̲s̲目錄,將openssl的lib…(rootpath)\deps目錄下。

第三,啟動命令列,執行命令 cd $(rootpath)\curl-7.65.3\winbuild,執行命令 KaTeX parse error: Undefined control sequence: \VC at position 16: (VSInstallPath)\̲V̲C̲\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使用流程如下圖所示:

在這裡插入圖片描述

Libcurl Post Get呼叫方法


第一,調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;
}