HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。
HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。HTTP是一个属于应用层的面向对象的协议,HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。
客户端发送一个HTTP请求到服务器的请求消息包括以下格式:
请求行(request line)、请求头部(header)、空行和请求数据四个部分组成
POST请求例子,使用Charles抓取的request:
1 POST / HTTP1.1
2 Host:www.wrox.com
User-Agent:Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.648; .NET CLR 3.5.21022)
Content-Type:application/x-www-form-urlencoded
Content-Length:40
Connection: Keep-Alive
3 //空行
4 name=Professional%20Ajax&publisher=Wiley
第一部分:请求行,第一行明了是post请求,以及http1.1版本。
第二部分:请求头部,第二行至第六行。
第三部分:空行,第七行的空行。
第四部分:请求数据,第八行。
HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。
Respose举例:
1 HTTP/1.1 200 OK
2 Date: Fri, 22 May 2009 06:07:21 GMT
Content-Type: text/html; charset=UTF-8
3 //空行
4 下面的html
第一部分:状态行,由HTTP协议版本号, 状态码, 状态消息 三部分组成。第一行为状态行,(HTTP/1.1)表明HTTP版本为1.1版本,状态码为200,状态消息为(ok)。
第二部分:消息报头,用来说明客户端要使用的一些附加信息。第二行和第三行为消息报头,
Date:生成响应的日期和时间;Content-Type:指定了MIME类型的HTML(text/html),编码类型是UTF-8
第三部分:空行,消息报头后面的空行是必须的
第四部分:响应正文,服务器返回给客户端的文本信息。空行后面的html部分为响应正文。
QUrlQuery 类提供了一种方法来操纵 URL 查询中的 key-value 对。
QUrlQuery 用来解析 URL 中的查询字符串,像下面这样:
上述的查询字符串在 URL 中 被用来传输选项,通常解码为多个 key-value 对。其列表包含了的两个条目,键为“type”和 “color”。QUrlQuery 也适用于从查询的各个组成部分创建一个查询字符串,为了 在 QUrl::setQuery() 中使用。
解析一个查询字符串最常见的方式是在构造函数中始化它,通过传递一个查询字符串。否则,可以使用 setQuery() 函数来设置要解析的查询。该函数也可用于解析具有非标准分割符的查询,在设置它们之后使用 setQueryDelimiters() 函数。
编码的查询字符串可以再次使用 query() 获得,这需要所有的内部存储项,并使用分隔符编码字符串。
简单使用eg:
// 基本 URL
QString baseUrl = "http://www.zhihu.com/search";
QUrl url(baseUrl);
// key-value 对
QUrlQuery query;
query.addQueryItem("type", "content");
query.addQueryItem("name", "Qt");
url.setQuery(query);
均为异步方式;
eg1:
QNetworkAccessManager *manager = new QNetworkAccessManager(this);
connect(manager, &QNetworkAccessManager::finished,this, &MyClass::replyFinished);
manager->get(QNetworkRequest(QUrl("http://qt-project.org")));
eg2:
QNetworkRequest request;
request.setUrl(QUrl("http://qt-project.org"));
request.setRawHeader("User-Agent", "MyOwnBrowser 1.0");
QNetworkReply *reply = manager->get(request);
connect(reply, &QIODevice::readyRead, this, &MyClass::slotReadyRead);
connect(reply, QOverload<QNetworkReply::NetworkError>::of(&QNetworkReply::error),this, &MyClass::slotError);
connect(reply, &QNetworkReply::sslErrors,this, &MyClass::slotSslErrors);
**同步方式举例:**函数实现是否能上外网
bool NetLiveWorker::IsWebOk()
{
return IsHostOnline("https://www.baidu.com/", 2000);
}
bool NetLiveWorker::IsHostOnline(QString strHostName, int nTimeoutmSeconds)
{
QNetworkRequest request(strHostName);
request.setRawHeader("Content-Type", "charset='utf-8'");
request.setRawHeader("Content-Type", "application/json");
//QNetworkAccessManager* naManager = new QNetworkAccessManager;
QNetworkAccessManager manager;
QEventLoop eventloop;
QTimer timer;
timer.singleShot(nTimeoutmSeconds, &eventloop, SLOT(quit()));
timer.start();
QNetworkReply* reply = manager.get(request);
QMetaObject::Connection conRet = QObject::connect(reply, SIGNAL(finished()), &eventloop, SLOT(quit()));
Q_ASSERT(conRet);
eventloop.exec(QEventLoop::ExcludeUserInputEvents); //开启事件循环
if (!timer.isActive())
{
//超时,未知状态
QObject::disconnect(reply, SIGNAL(finished()), &eventloop, SLOT(quit()));
reply->abort();
reply->deleteLater();
return false;
}
if (reply->error() != QNetworkReply::NoError)
{
//qDebug() << "error = " <error();
reply->abort();
reply->deleteLater();
return false;
}
bool bRes = reply->readAll().length() > 0;
reply->abort();
reply->deleteLater();
return bRes;
}
post方法提供了二个重载方法,每个方法针对有特定的场景
QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODevice *data)
QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, const QByteArray &data)
QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QHttpMultiPart *multiPart)
eg1: 异步方式,同步方式同上
QUrl url(m_strApiHead + "iot-server/api/pen/device/login");
QUrlQuery postData;
postData.addQueryItem("wifi_mac", pconf->getWifiMac());
postData.addQueryItem("sn", pconf->getSN());
postData.addQueryItem("sig",checksum);
QNetworkAccessManager netManager;
QNetworkRequest request(url);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QNetworkReply *pNetworkResponse = netManager.post(request,postData.toString(QUrl::FullyEncoded).toUtf8());
QObject::connect(pNetworkResponse, &QNetworkReply::finished, [=]{
QByteArray res = pNetworkResponse->readAll();
qDebug() <<"sendApiLogin replay " << res;
QJsonObject json_object = QJsonDocument::fromJson(res).object();
});
eg2:QHttpMultiPart 发送文件
QUrl url( m_strApiHead + "iot-server/api/pen/device/picsearch");
QImage img(sfPath);
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
QHttpPart textPart;
//stamp
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"stamp\""));
textPart.setBody(stamp.toLocal8Bit());
multiPart->append(textPart);
//width
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"image_width\""));
textPart.setBody(QString("%1").arg(width).toLocal8Bit());
multiPart->append(textPart);
//height
textPart.setHeader(QNetworkRequest::ContentDispositionHeader, QVariant("form-data; name=\"image_height\""));
textPart.setBody(QString("%1").arg(height).toLocal8Bit());
multiPart->append(textPart);
//
QFile *file = new QFile(sfPath);
if (file->open(QIODevice::ReadOnly))
{
qDebug() << "sendApiSearchQuesResults open file " << sfPath << "success" ;
QHttpPart filePart;
filePart.setHeader(QNetworkRequest::ContentDispositionHeader,
QString("form-data; name=\"file\"; filename=\"%1\"").arg(filename));
filePart.setBodyDevice(file);
file->setParent(multiPart); // file deleted on the destruction of multiPart
multiPart->append(filePart);
}
else {
qDebug() << sfPath << "ultiPart->append(filePart) open failed";
}
multiPart->setBoundary("---wmm---"); //设置分隔符
QNetworkAccessManager netManager;
QNetworkRequest request(url);
QNetworkReply *pNetworkResponse = netManager.post(request,multiPart);
multiPart->setParent(pNetworkResponse);
QObject::connect(pNetworkResponse, &QNetworkReply::finished, [=]{
file->close();
QByteArray res = pNetworkResponse->readAll();
QTextCodec *tc = QTextCodec::codecForName("UTF8");
QString str = tc->toUnicode(res);
//qDebug() <<"sendApiSearchQuesResults replay " << str;
QJsonObject json_object = QJsonDocument::fromJson(res).object();
pNetworkResponse->deleteLater();
});
qt中http提供了很多方便的类来实现post、get方法
其中主要有
1 QNetworkAccessManager
2 QUrlQuery
3 QNetworkRequest
4 QNetworkReply
后续会提供这些类的详细用法,和应用场景
QNetworkAccessManager用法: https://editor.csdn.net/md/?articleId=114499807
QUrlQuery 详解:link.
Qt之 Post方法上传图片到服务器两种方式Base64流和File :https://editor.csdn.net/md/?articleId=114794119.
Qt之 四种常见的 POST 提交数据方式: https://editor.csdn.net/md/?articleId=114795085.