想要自己做一个类似 Apache 的服务器软件,因为是某个 Qt 项目中的模块,于是使用了 QHttpServer 库,使用起来也很方便:
1 2 3 4 5 6 7
| QHttpServer *server = new QHttpServer; connect(server, SIGNAL(newRequest(QHttpRequest*, QHttpResponse*)), this, SLOT(serverHandle(QHttpRequest*, QHttpResponse*)));
if (!server->listen(port)) { statusLabel->setText("开启服务端失败!"); }
|
这样,每当浏览器访问 localhost:port
的时候,则会进入 serverHandle
槽。
1 2 3 4 5 6 7 8
| void MainWindow::requestHandle(QHttpRequest *req, QHttpResponse *resp) { auto url = req->url().toString(); auto method = req->method(); auto &headers = req->headers(); auto body = req->body(); }
|
但是当收到 post 的数据,想要获取 req->body()
的时候,会发现取到的结果总是空的。
经过一番研究,发现 request 是以流的形式传输,如果不调用 storeBody,那么 request 就不会尝试下载 body 的数据。
调用 req->storeBody()
后,当数据存储结束时,会触发 end()
和 data(const&QByteArray)
信号。
尝试使用 QEventLoop:
1 2 3 4
| req->storeBody(); QEventLoop loop; connect(req, &QHttpRequest::end, &loop, &QEventLoop::quit); loop.exec();
|
但是这种发现 req->storeBody()
并不会单独开一个线程,loop->exec()
后会导致 store 堵住,无法实现。
因此,还是只能采用信号槽的形式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class RequestBodyHelper : public QObject { Q_OBJECT public: RequestBodyHelper(QHttpRequest* req, QHttpResponse* resp) : req(req), resp(resp) { }
void waitBody() { req->storeBody(); connect(req, SIGNAL(end()), this, SLOT(end())); }
public slots: void end() { emit finished(req, resp); this->deleteLater(); }
signals: void finished(QHttpRequest* req, QHttpResponse* resp);
private: QHttpRequest* req; QHttpResponse* resp; };
|
1 2 3 4 5 6 7 8 9 10 11
| void MainWindow::serverHandle(QHttpRequest *req, QHttpResponse *resp) { if (req->method() == QHttpRequest::HttpMethod::HTTP_GET) { return requestHandle(req, resp); } RequestBodyHelper *helper = new RequestBodyHelper(req, resp); helper->waitBody(); connect(helper, SIGNAL(finished(QHttpRequest *, QHttpResponse *)), this, SLOT(requestHandle(QHttpRequest *, QHttpResponse *))); }
|
这样就能使用 req->body()
来获取 post 的数据了。