天天看點

Qt 使用 curl

Qt 使用 curl

Qt 已經提供了 QNetworkAccessManager 用于 Http 通路,Qt 通路網絡的 HttpClient 對其進行了簡單封裝,如下就可以進行 GET 請求:

HttpClient("http://localhost:8080/device").get([](const QString &response) {
qDebug() << response;           

但是,在非 Qt 項目中就不能使用 QNetworkAccessManager 了,還有就是因為 curl 成熟、強大、跨平台,可能有些項目更希望使用 curl,是以在此以 Windows MinGW 的 Qt 項目為例,介紹 curl 的內建使用。

編譯 curl

curl 沒有提供編譯好的庫,需要自己編譯,可按照下面的步驟進行(curl 相關的目錄根據對應的版本好做出修改)

Windows 中可使用 VS2013 編譯 curl,是以當然是要先安裝 VS2013

到 https://curl.haxx.se/download.html 下載下傳 curl 源碼,選擇最新版吧,解壓得到的壓縮包儲存到

C:/curl-7.56.0

Win + CMD 打開指令行

“C:\Program Files (x86)\Microsoft Visual Studio

12.0\VC\bin\vcvars32.bat” 設定 VS 的環境變量,隻會目前 CMD 生效

cd C:\curl-7.56.0\winbuild

nmake /f Makefile.vc mode=dll VC=12 進行編譯動态編譯,也可以閱讀 BUILD.WINDOWS.txt

檢視更詳細的資訊

編譯後的庫檔案儲存到

C:\curl-7.56.0\builds\libcurl-vc12-x86-release-dll-ipv6-sspi-winssl,複制此目錄到

C 盤根目錄,重命名為 libcurl,目錄結構如下:

C:/

└── libcurl
├── bin
│ ├── curl.exe
│ └── libcurl.dll
├── include
│ └── curl
│ ├── curl.h
│ ├── curlver.h
│ ├── easy.h
│ ├── mprintf.h
│ ├── multi.h
│ ├── stdcheaders.h
│ ├── system.h
│ └── typecheck-gcc.h
└── lib
├── libcurl.exp
└── libcurl.lib           

使用 curl

Qt Creator 中建立一個 Qt 項目,pro 檔案裡加上 curl 的庫資訊

INCLUDEPATH += C:/libcurl/include
LIBS += C:/libcurl/bin/libcurl.dll           

這裡不需要動态庫的索引 .lib 檔案,也不需要把 .lib 轉換成 .a,直接使用 .dll 就可以了,MinGW 的編譯器能夠識别,和 VS 的編譯器有些不一樣。

接下來就可以使用 curl 發送 Http 請求了

#include <QDebug>
#include <cstring>
#include <curl/curl.h>
// curl 讀取到的資料儲存到 std::string
size_t curlSaveResponseToStdString(void *contents, size_t size, size_t nmemb, std::string *s) {
size_t newLength = size * nmemb;
size_t oldLength = s->size();
s->resize(oldLength + newLength);
std::copy((char*)contents, (char*)contents+newLength, s->begin()+oldLength);
return size * nmemb;
}
int main(int argc, char *argv[]) {
// 初始化 curl
CURL *curl = curl_easy_init();
if (curl) {
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "http://www.qtdebug.com/html/data.json"); // 設定要通路的網址
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlSaveResponseToStdString); // 告訴 curl 儲存響應到 string 中
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); // 請求的響應儲存到變量 response 中
curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); // 0 不輸出請求的詳細資訊,1 輸出
CURLcode code = curl_easy_perform(curl);
if (code == CURLE_OK) {
// std::cout << response << std::endl; // 中文亂碼,因為 std::string 對中文的支援不好
// qDebug() << QString::fromUtf8(response.data()); // response.data() 傳回的是 UTF-8 的位元組資料
qDebug() << QString::fromStdString(response); // 使用 qDebug() 輸出,UTF-8 的中文不會亂碼
}
} else {
qDebug() << "Error";
}
// 釋放 curl 資源
curl_easy_cleanup(curl);
return 0;
}           

編譯正常,運作時程式異常結束,這是因為程式找不到 libcurl.dll,把 libcurl.dll 複制到編譯出來的 exe 目錄,再次運作程式,看到控制台輸出

“{\”name\”: \”Alice\”}\n”           

哈哈,curl 終于內建到我們的項目裡了,至于 curl 的更多使用,請執行搜尋相關教程即可,在這裡就不贅述了,可以看看 ​C++ 用libcurl庫進行http通訊網絡程式設計​​,這篇文章不錯 。

上面示範了 GET 請求,POST 請求隻需要設定 CURLOPT_POST 為 1 即可:

if (curl) {
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "http://192.168.10.52:8080/rest");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlSaveResponseToStdString);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl,CURLOPT_POST, 1); // POST 請求
curl_easy_setopt(curl,CURLOPT_POSTFIELDS, "name=趙子龍&department=Dev"); // POST 參數: GET 請求中的中文要進行 URL 編碼,否則提示錯誤
CURLcode code = curl_easy_perform(curl);
if (code == CURLE_OK) {
qDebug() << QString::fromUtf8(response.data());
}
}           

參考案例

最後,附上一個小程式,包含了 GET 和 POST 的請求,作為參考:

#include <QDebug>
#include <string>
#include <iostream>
#include <curl/curl.h>
std::string get(const char* url, CURLcode *code = NULL, std::list<const char *> headers = std::list<const char *>());
std::string post(const char* url, const char* data = NULL, bool jsonBody = false, CURLcode *code = NULL, std::list<const char *> headers = std::list<const char *>());
int main(int argc, char *argv[]) {
CURLcode code;
std::string r1 = get("http://qtdebug.com/html/data.json");
qDebug() << QString::fromUtf8(r1.data());
qDebug() << "------------------------------------------------";
std::string r2 = post("http://eplatform.edu-edu.com.cn/live/api/auth/login", "{ \"username\": \"u1\", \"password\": \"abcd\"}", true);
qDebug() << QString::fromUtf8(r2.data());
qDebug() << "------------------------------------------------";
std::string r3 = get("http://eplatform.edu-edu.com.cn/live/api/channels/mine", &code, {"Authorization: JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjU4NjM1Y2Y4NGY0N2M4MGYyNGI1NDQ5NyIsImlhdCI6MTUwOTA3NjY5MCwiZXhwIjoxNTA5MTYzMDkwfQ.6nLBnhjTYJgwjwFf_Lf0LreKryrQ6ITdT-PcGAPhKB8"});
qDebug() << QString::fromUtf8(r3.data());
return 0;
}
// curl 讀取到的資料儲存到 std::string
size_t curlSaveResponseToStdString(void *contents, size_t size, size_t nmemb, std::string *s) {
size_t newLength = size * nmemb;
size_t oldLength = s->size();
s->resize(oldLength + newLength);
std::copy((char*)contents, (char*)contents+newLength, s->begin()+oldLength);
return size * nmemb;
}
/**
* @brief 執行 HTTP GET 請求
* @param url 請求的 URL
* @param code 請求傳回的狀态碼的指針
* @param headers 請求頭
* @return 請求執行成功時傳回響應的字元串,失敗則傳回空字元串,請求是否執行成功可以通過 code 進行判斷
*/
std::string get(const char* url, CURLcode *code, std::list<const char *> headers) {
std::string response;
// 初始化 curl
CURL *curl = curl_easy_init();
if (curl) {
struct curl_slist *tempHeaders = NULL;
std::list<const char *>::const_iterator iter;
for (iter = headers.cbegin(); iter != headers.cend(); ++iter) {
tempHeaders = curl_slist_append(tempHeaders, *iter);
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, tempHeaders);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlSaveResponseToStdString);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
CURLcode temp = curl_easy_perform(curl);
if (code != NULL) {
*code = temp;
}
curl_slist_free_all(tempHeaders); /* free the header list */
} else {
if (code != NULL) {
*code = CURLE_FAILED_INIT;
}
}
// 釋放 curl 資源
curl_easy_cleanup(curl);
return response;
}
/**
* @brief 執行 HTTP POST 請求
* @param url 請求的 URL
* @param data 請求的參數
* @param jsonBody 如果為 true,則請求的參數是 JSON 格式,否則為 Form 表單的格式 key1=value1&key2=value2&...
* @param code 請求傳回的狀态碼的指針
* @param headers 請求頭
* @return 請求執行成功時傳回響應的字元串,失敗則傳回空字元串,請求是否執行成功可以通過 code 進行判斷
*/
std::string post(const char* url, const char* data, bool jsonBody, CURLcode *code, std::list<const char *> headers) {
std::string response;
// 初始化 curl
CURL *curl = curl_easy_init();
if (curl) {
// Headers
struct curl_slist *tempHeaders = NULL;
std::list<const char *>::const_iterator iter;
for (iter = headers.cbegin(); iter != headers.cend(); ++iter) {
tempHeaders = curl_slist_append(tempHeaders, *iter);
}
if (jsonBody) {
tempHeaders = curl_slist_append(tempHeaders, "Accept: application/json; charset=utf-8");
tempHeaders = curl_slist_append(tempHeaders, "Content-Type: application/json");
}
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, tempHeaders);
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlSaveResponseToStdString);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
curl_easy_setopt(curl,CURLOPT_POST, 1); // POST 請求
curl_easy_setopt(curl,CURLOPT_POSTFIELDS, data); // POST 參數
CURLcode temp = curl_easy_perform(curl);
if (code != NULL) {
*code = temp;
}
curl_slist_free_all(tempHeaders); /* free the header list */
} else {
if (code != NULL) {
*code = CURLE_FAILED_INIT;
}
}
// 釋放 curl 資源
curl_easy_cleanup(curl);
return response;
}
           

【領QT開發教程學習資料,點選下方連結莬費領取↓↓,先碼住不迷路~】

點選這裡:「連結」