文章目录
- HTTP Client
- 核心API
- QNetworkAccessManager
- QNetworkRequest
- QNetworkReply
- 代码示例
本文不涉及 HTTP 的相关前置知识,前置知识可参看
URL概念及组成
HTTP请求
HTTP响应及Cookie原理
HTTP Client
进行 Qt 开发时,和服务器之间的通信很多时候也会使用 HTTP 协议
- 通过 HTTP 从服务器获取数据
- 通过 HTTP 向服务器提交数据
因为 Qt 开发方向之一是图形化客户端开发,所以 Qt 只提供了客户端的 HTTP 通信,基本不使用 Qt 开发服务器
核心API
主要使用的类有三个,QNetworkAccessManager
,QNetworkRequest
,QNetworkReply
QNetworkAccessManager
QNetworkAccessManager
提供了 HTTP客户端的 核心操作
例如:
API | 说明 |
---|---|
get(const QNetworkRequest& request) | 发起一个 HTTP GET 请求,返回值是 QNetworkReply 的对象指针。主要用于从服务器获取数据 |
post(const QNetworkRequest& request, const QByteArray &data) | 发起一个 HTTP POST 请求,返回 QNetworkReply 对象指针 主要用于向服务器提交/上传数据 |
HTTP 请求报文格式如下:
post请求中,data是要提交/上传的数据,
QNetworkRequest
只表示一个 HTTP 请求(不包含请求体
)
所以如果需要发送一个带有请求体的 HTTP请求,需要在 post 方法中通过单独的参数传入请求体数据
QNetworkRequest
QNetworkRequest
只表示一个 HTTP 请求(不包含请求体
)
常用API:
API | 说明 |
---|---|
QNetworkRequest(const QUrl& url) | 通过 URL 构造一个 HTTP 请求 |
setHeader(QNetworkRequest::KnownHeaders header, const QVariant &value) | 设置请求头 |
QNetworkRequest::KnownHeaders
URL 的组成可参看 URL概念及组成
请求头都为 key-value 结构,QNetworkRequest::KnownHeaders
是一个枚举类型,用来表示请求头的 key,常用取值如下:
取值 | 说明 |
---|---|
ContentTypeHeader | 描述 请求体body 的类型 |
ContentLengthHeader | 描述 请求体body 的长度 |
LocationHeader | 用于重定向报文中指定重定向地址(响应中使用,请求用不到) |
CookieHeader | 设置 cookie |
UserAgentHeader | 设置 User-Agent |
QVariant
QVariant 可以存储各种类型的数据,包括整数、字符串、日期等。
代码示例:设置请求头
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QVariant>
#include <QUrl>
int main() {
QNetworkAccessManager manager;
QNetworkRequest request(QUrl("http://example.com"));
// 设置Content-Type头
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
// 设置User-Agent头
request.setHeader(QNetworkRequest::UserAgentHeader, "MyApp/1.0");
// 发送请求
QNetworkReply *reply = manager.get(request);
// 这里可以连接信号与槽来处理响应
// connect(reply, &QNetworkReply::finished, ...);
return 0;
}
QNetworkReply
QNetworkReply
表示一个 HTTP 响应
API | 说明 |
---|---|
error() | 返回值是NetworkError ,获取出错状态 |
errorString() | 返回值是 QString 获取出错原因的文本 |
readAll() | 读取 响应体body |
header(QNetworkRequest::KnownHeaders header) | 通过 header 获取对应的 value值 |
NetworkError
是一个枚举类,集合了在处理请求期间发现的所有可能的错误条件。
其中,常用枚举值如下:
QNetworkReply::NoError
表示没有错误发生QNetworkReply::ConnectionRefusedError
表示连接被拒绝,通常意味着服务器无法响应连接请求QNetworkReply::RemoteHostClosedError
表示远程主机关闭了连接QNetworkReply::HostNotFoundError
表示无法找到主机。通常意味着DNS解析失败QNetworkReply::TimeoutError
表示请求超时QNetworkReply::SslHandshakeFailedError
表示SLL/TLS 握手失败,通常意味着SSL证书验证失败或其他SLL/TLS错误,使用https通信时可能发生
当客户端收到完整的响应数据后,会触发
QNetworkReply::finished
信号
可通过信号槽机制,及时高效的处理响应数据
代码示例
给服务器发送一个 GET 请求
- 编写 UI文件,创建界面,其中包含一个
QLineEdit
,QPushButton
,和一个QPlainTextEdit
。再使用布局管理器规范界面布局
2. 编写 widget.h
,声明按钮槽函数和QNetworkAccessManager
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private slots:
//"发送"按钮的点击信号的槽函数
void on_pushButton_clicked();
private:
Ui::Widget *ui;
QNetworkAccessManager *manager;
};
- 编写
widget.cpp
,实例化并实现槽函数
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//实例化
manager = new QNetworkAccessManager(this);
}
void Widget::on_pushButton_clicked()
{
//1. 获取输入栏url,构造URL
const QString &text = ui->lineEdit->text();
QUrl url(text);
//2. 构造并发送请求
QNetworkRequest request(url);
QNetworkReply *responce = manager->get(request);
//3. 连接信号槽,收到完整响应才读取数据
connect(responce, &QNetworkReply::finished, this, [=](){
if(responce->error() == QNetworkReply::NoError)
{
//数据没有问题
QString html = responce->readAll();
ui->plainTextEdit->setPlainText(html);
}
else//有问题
QMessageBox::critical(this, "HTTP响应出错", responce->errorString());
});
}
次数使用
QPlainTextEdit
,将响应体中的html文本转化为纯文本,如果使用类似QTextEdit
,会对html文本进行富文本解析,若得到的 html 代码复杂,会导致界面渲染缓慢甚至卡住
运行结果如下:
结束语
感谢你的阅读
如果觉得本篇文章对你有所帮助的话,不妨点个赞支持一下博主,拜托啦,这对我真的很重要。