QT - HTTP网络请求,使用curl模拟Network模块

一、Qt自带的网络模块Network,http请求代码如下:

	QNetworkAccessManager manager;
	QNetworkReply * reply = manager.get(QNetworkRequest(QUrl("https://www.baidu.com")));

	QEventLoop loop;
	connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
	loop.exec();

	QString result = reply->readAll();

	qDebug() << result;

	reply->deleteLater();

二、使用curl模拟

1、模拟QNetworkAccessManager类

#pragma once
#include 
#include "NetworkRequest.h"
#include "NetworkReply.h"

class CNetworkManager : public QObject
{
	Q_OBJECT
public:
	explicit CNetworkManager(){}
	virtual ~CNetworkManager(){}
public:
	CNetworkReply* get(CNetworkRequest& request);
	CNetworkReply* post(CNetworkRequest& request, const QString& data);
};

-------------------------------

CNetworkReply* CNetworkManager::get(CNetworkRequest& request)
{
	CNetworkReply * reply = new CNetworkReply(request);
	reply->start();
	return reply;
}

CNetworkReply* CNetworkManager::post(CNetworkRequest& request, const QString& data)
{
	if(!data.isEmpty()) request.setPostData(data);
	CNetworkReply * reply = new CNetworkReply(request);
	reply->start();
	return reply;
}

2、模拟QNetworkRequest类

class CNetworkRequest :public QObject
{
	Q_OBJECT
public:
	CNetworkRequest(){}
	CNetworkRequest(const QUrl& url){ m_url = url.toString(); }
	virtual ~CNetworkRequest(){}

	void setUrl(const QUrl& url) { m_url = url.toString(); }
	void setPostData(const QString& data) { m_postdata = data; }
	void setProxy(const QString& proxy, int port = 0) {
		m_proxy = proxy;
		if (port) m_proxy.append(":").append(QString::number(port));
	}
	void setCookieFile(const QString& cookieFile) { m_cookieFile = cookieFile; }
	void setHeader(const QString& key, const QString& value){ m_headers.append(key + ":" + value); }

	QString getUrl() { return m_url; }
	QString getProxy() { return m_proxy; }
	QString getPostData() { return m_postdata; }
	QString getCookieFile() { return m_cookieFile; }
	QStringList getHeaders() { return m_headers; }
private:
	QString m_url;
	QString m_proxy;
	QString m_postdata;
	QString m_cookieFile;
	QStringList m_headers;
};

3、模拟QNetworkReply

class CNetworkReply :public QThread
{
	Q_OBJECT
public:
	CNetworkReply(CNetworkRequest& request);
	virtual ~CNetworkReply();

	bool isOK() { return m_errMsg.isEmpty(); }

	QByteArray readAll() { return m_bodyContent; }
	QByteArray readHeader() { return m_headerContent; }
	QByteArray getErrorMsg() { return m_errMsg; }

	virtual void run() override;

signals:
	void finished(CNetworkReply* reply);
private:
	CURL * m_curl;
	struct curl_slist *m_headers;

	QByteArray m_bodyContent;
	QByteArray m_headerContent;
	QByteArray m_errMsg;
};

-------------------------

size_t curl_callback(void * ptr, size_t size, size_t nmemb, void * stream)
{
	((QByteArray*)stream)->append((char*)ptr, size*nmemb);
	return size*nmemb;
}
CNetworkReply::CNetworkReply(CNetworkRequest& request)
{
	curl_global_init(CURL_GLOBAL_ALL);
	m_curl = curl_easy_init();

	// 配置url
	if (!request.getUrl().isEmpty()){
		curl_easy_setopt(m_curl, CURLOPT_URL, request.getUrl().toUtf8().data());
	}
	// 配置ssl校验
	if (request.getUrl().startsWith("https")) {
		curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 0L);
		curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYHOST, 0L);
	}
	// 配置代理
	if (!request.getProxy().isEmpty()){
		curl_easy_setopt(m_curl, CURLOPT_PROXY, request.getProxy().toUtf8().data());
	}
	// 配置post参数
	if (!request.getPostData().isEmpty()){
		curl_easy_setopt(m_curl, CURLOPT_POST, 1L);
		curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, request.getPostData().toUtf8().data());
	}
	// 配置请求头信息
	m_headers = Q_NULLPTR;
	if (!request.getHeaders().isEmpty()){
		for (QString header : request.getHeaders()) m_headers = curl_slist_append(m_headers, header.toUtf8().data());
		curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, m_headers);
	}
	// 配置cookie
	if (!request.getCookieFile().isEmpty()){
		curl_easy_setopt(m_curl, CURLOPT_COOKIEFILE, request.getCookieFile().toUtf8().data());
		curl_easy_setopt(m_curl, CURLOPT_COOKIEJAR, request.getCookieFile().toUtf8().data());
	}
	// 配置内容回调信息
	curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, curl_callback);
	curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &m_bodyContent);
	// 配置响应头信息
	curl_easy_setopt(m_curl, CURLOPT_HEADER, 0L);
	curl_easy_setopt(m_curl, CURLOPT_HEADERFUNCTION, curl_callback);
	curl_easy_setopt(m_curl, CURLOPT_HEADERDATA, &m_headerContent);
}

CNetworkReply::~CNetworkReply()
{
	if (m_curl) curl_easy_cleanup(m_curl);
	curl_global_cleanup();
}

void CNetworkReply::run()
{
	// 睡眠50毫秒
	currentThread()->msleep(50);

	CURLcode resCode = curl_easy_perform(m_curl);
	if (m_headers) curl_slist_free_all(m_headers);

	if (resCode != CURLE_OK) m_errMsg.append("curl_easy_perform() failed: ").append(curl_easy_strerror(resCode));

	emit finished(this);
}


三、最后的调用方法,和Qt的如出一辙

	CNetworkManager manager;
	CNetworkReply * reply = manager.get(CNetworkRequest(QUrl("https://www.baidu.com")));

	QEventLoop loop;
	connect(reply, &CNetworkReply::finished, &loop, &QEventLoop::quit);
	loop.exec();

	QString result = reply->readAll();

	qDebug() << result;

	reply->deleteLater();








你可能感兴趣的:(QT)