在Qt中使用QtWebApp搭建HTTP服务器

CSDN 2024-08-04 10:33:01 阅读 58

最近在开发Qt的http服务器功能,研究比较了一番,选择了QtWebApp方案,相对其他开源库,比较推荐使用该方案,功能齐全,简单易用,如果赶项目的话,极力推荐。

下面介绍一下Qt集成QtWebApp步骤:

一、Qt集成QtWebApp步骤:

1、下载QtWebApp源码:KingJamesGyq/QtWebApp

把源码拉下来到本地,将httpsever目录整个移植到自己的项目工程下。

2、在pro文件包含httpserver

<code>include ($$PWD/httpserver/httpserver.pri)

这样就完成集成源码了,剩下的就是根据你自己的业务需求去开发了,细节可以参考Demo1和Demo2。

二、在Qt中使用QtWebApp搭建HTTP服务器

第一步 下载QtWebApp导入工程中

工程示例:

第二步 编写配置文件WebApp.ini

<code>host=192.168.255.128;服务ip地址

port=8080;端口号

minThreads=4;4个线程始终保持运行状态

maxThreads=100;并发工作线程的最大数量

cleanupInterval=60000

readTimeout=60000

maxRequestSize=16000

maxMultiPartSize=10000000

第三步 加载配置文件,创建HTTP侦听器对象

main.cpp

#include "httplistener.h"

#include "httprequesthandler.h"

#include "RequestMapper.h" //自定义类请求映射器类

QSettings* listenerSettings=

new QSettings(QCoreApplication::applicationDirPath()+"/WebApp.ini",QSettings::IniFormat);

new stefanfrings::HttpListener(listenerSettings, new RequestMapper());

第四步 自定义类请求映射器类

RequestMapper.h

#ifndef REQUESTMAPPER_H

#define REQUESTMAPPER_H

#include "httprequesthandler.h"

using namespace stefanfrings;

#include "HelloController.h"

class RequestMapper:public HttpRequestHandler

{

public:

RequestMapper();

void service(HttpRequest& request, HttpResponse& response);

private:

HelloController m_helloController;

};

#endif // REQUESTMAPPER_H

RequestMapper.cpp

#include "RequestMapper.h"

#include "json.hpp"

#include <string>

using namespace std;

using namespace nlohmann;

RequestMapper::RequestMapper()

{

}

void RequestMapper::service(HttpRequest &request, HttpResponse &response)

{

QByteArray path=request.getPath();

QByteArray method = request.getMethod();

QByteArray nm = request.getParameter("nm");

qDebug() << "RequestMapper: path=" << path.data();

qDebug() << "RequestMapper: method=" << method.data();

qDebug() << "RequestMapper: nm=" << nm.data();

if ( path=="/hello") {code>

m_helloController.service(request,response);

}

}

第五步 自定义业务请求处理类

HelloController .h

#ifndef HELLOCONTROLLER_H

#define HELLOCONTROLLER_H

#include <QObject>

#include "httprequesthandler.h"

using namespace stefanfrings;

#include "json.hpp"

using namespace nlohmann;

#include <string>

using namespace std;

class HelloController : public QObject

{

Q_OBJECT

public:

explicit HelloController(QObject *parent = 0);

void service(HttpRequest& request, HttpResponse& response);

signals:

public slots:

};

#endif // HELLOCONTROLLER_H

HelloController.cpp

#include "HelloController.h"

HelloController::HelloController(QObject *parent) : QObject(parent)

{

}

void HelloController::service(HttpRequest &request, HttpResponse &response)

{

QByteArray body = request.getBody();

qDebug() << body;

json res;

res["code"] = 200;

res["mesage"] = "success";

string str = res.dump(4);

// response.setStatus(404);

response.write(str.c_str());

}

第六步 测试

服务运行示例

浏览器发请求示例

另外:其他的映射和控制器写法:

requestmapper.h

<code>#ifndef REQUESTMAPPER_H

#define REQUESTMAPPER_H

#include "QtWebApp/httpserver/httprequesthandler.h"

using namespace stefanfrings;

/*

The request mapper dispatches incoming HTTP requests to controller classes

depending on the requested path.

*/

class RequestMapper : public HttpRequestHandler {

Q_OBJECT

Q_DISABLE_COPY(RequestMapper)

public:

/*

Constructor.

@param parent Parent object

*/

RequestMapper(QObject* parent=0);

/*

Destructor.

*/

~RequestMapper();

/*

Dispatch incoming HTTP requests to different controllers depending on the URL.

@param request The received HTTP request

@param response Must be used to return the response

*/

void service(HttpRequest& request, HttpResponse& response);

// 拦截未授权操作

bool preHandle(HttpRequest& request, HttpResponse& response);

};

#endif // REQUESTMAPPER_H

requestmapper.cpp

#include "requestmapper.h"

#include "global.h"

#include "controller/logincontroller.h"

#include "controller/funcvercodecontroller.h"

#include "controller/sysmsgcontroller.h"

#include "controller/sysusercontroller.h"

#include "controller/commoncontroller.h"

#include "controller/sysmenucontroller.h"

#include "controller/sysdiccontroller.h"

#include "controller/sysrolecontroller.h"

#include "controller/sysdeptcontroller.h"

#include "controller/syslogcontroller.h"

#include "controller/funcmonitorcontroller.h"

#include "controller/sysusermsgcontroller.h"

#include "controller/funcsmscontroller.h"

#include "controller/funcemailcontroller.h"

#include "controller/funcloadcontroller.h"

#include "controller/funcexportcontroller.h"

#include<qthread.h>

RequestMapper::RequestMapper(QObject* parent)

:HttpRequestHandler(parent)

{

qDebug("RequestMapper: created");

qDebug()<<".................RequestMapper created......................currentThreadId():"<<QThread::currentThreadId();

}

RequestMapper::~RequestMapper()

{

qDebug("RequestMapper: deleted");

}

void RequestMapper::service(HttpRequest& request, HttpResponse& response)

{

qDebug()<<"..............RequestMapper::service..................currentThreadId():"<<QThread::currentThreadId();

QByteArray path = request.getPath().toLower();

QString tmp = QString(path);

qDebug("RequestMapper::service e");

//实现跨域访问,js 调用API 提供了支持。

response.setHeader("Connection", "keep-alive");

auto origin = request.getHeader("Origin");

response.setHeader("Access-Control-Allow-Origin", origin);

response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS");

response.setHeader("Access-Control-Allow-Headers", "X-PINGOTHER,Content-Type,x-token,access_token");

response.setHeader("Access-Control-Max-Age", "86400");

response.setHeader("Vary", "Accept-Encoding,Origin");

response.setHeader("Keep-Alive", "timeout=2,max=99");

response.setHeader("Access-Control-Allow-Credentials", "true");

//set api header

response.setHeader("Content-Type", "application/json; charset=utf-8");

//response.setHeader("Access-Control-Allow-Origin", "*"); // also important , if not set , the html application wont run.

if (request.getMethod() == "OPTIONS")

{

response.setStatus(200,"OK");

qDebug("RequestMapper: finished request");

// Clear the log buffer

return;

}

//拦截部分,做token校验

if (path.startsWith("/func")

|| path.startsWith("/sys")

|| path.startsWith("/monitor/"))

{

if(!preHandle(request, response))

return;

}

if (path.startsWith("/login") || path.startsWith("/logout"))

{

LoginController().service(request, response);

}

else if (path.startsWith("/vercode"))

{

FuncVercodeController().service(request, response);

}

else if (path.startsWith("/func/message/user/"))

{

SysUserMsgController().service(request, response);

}

else if (path.startsWith("/func/message/sys/"))

{

SysMsgController().service(request, response);

}

else if (path.startsWith("/sys/user/"))

{

SysUserController().service(request, response);

}

else if (path.startsWith("/sys/menu/"))

{

SysMenuController().service(request, response);

}

else if (path.startsWith("/sys/dic/"))

{

SysDicController().service(request, response);

}

else if (path.startsWith("/sys/role/"))

{

SysRoleController().service(request, response);

}

else if (path.startsWith("/sys/dept/"))

{

SysDeptController().service(request, response);

}

else if (path.startsWith("/sys/log/"))

{

SysLogController().service(request, response);

}

else if (path.startsWith("/func/sms/"))

{

FuncSmsController().service(request, response);

}

else if (path.startsWith("/sys/email/"))

{

FuncEmailController().service(request, response);

}

else if (path.startsWith("/func/upload/"))

{

FuncLoadController().service(request, response);

}

else if (path.startsWith("/func/export/"))

{

FuncExportController().service(request, response);

}

else if (path.startsWith("/monitor"))

{

FuncMonitorController().service(request, response);

}

else if (path.startsWith("/common"))

{

CommonController().service(request, response);

}

else

{

staticFileController->service(request, response);

}

qDebug("RequestMapper: finished request");

// Clear the log buffer

if (logger)

{

// logger->clear();

}

}

// 拦截未授权操作

bool RequestMapper::preHandle(HttpRequest& request, HttpResponse& response)

{

// token校验不通过,返回1001

ResultJson result(1001, false, QStringLiteral("token已失效"));

QString accessToken = request.getHeader("access_token");

if(accessToken == NULL || accessToken.isEmpty())

accessToken = request.getParameter("access_token");

if(accessToken == NULL || accessToken.isEmpty())

{

result.failedMsg(QStringLiteral("找不到token"));

ResponseUtil::replyJson(response, result);

//staticFileController->service(request, response);

return false;

}

//根据token登录

QString username = JwtUtil::getUsername(accessToken);

if(username == NULL || username.isEmpty())

{

ResponseUtil::replyJson(response, result);

//staticFileController->service(request, response);

return false;

}

//判断token是否有效

QString token_key = username + "_token";

QString saveToken = CacheApi::instance()->get(token_key);

if(saveToken != accessToken)

{

ResponseUtil::replyJson(response, result);

//staticFileController->service(request, response);

return false;

}

//刷新token

CacheApi::instance()->insert(token_key, accessToken, JwtUtil::EXPIRED_TIME);

return true;

}

logincontroller.h

#ifndef LOGINCONTROLLER_H

#define LOGINCONTROLLER_H

#include "global.h"

#include <QMap>

using namespace stefanfrings;

class LoginController: public HttpRequestHandler {

Q_OBJECT

Q_DISABLE_COPY(LoginController)

public:

LoginController();

void service(HttpRequest& request, HttpResponse& response);

void login(HttpRequest& request, HttpResponse& response); //登录

void logout(HttpRequest& request, HttpResponse& response); //退出

private:

SqlHelper* m_pHelper;

typedef void (LoginController::*pServFunc)(HttpRequest& request, HttpResponse& response);

QMap<QString, pServFunc> m_mapFunc;

};

#endif // LOGINCONTROLLER_H

logincontroller.cpp

#include "logincontroller.h"

#include <QCryptographicHash>

#include <qthread.h>

LoginController::LoginController()

{

qDebug()<<"....................LoginController........................currentThreadId():"<<QThread::currentThreadId();

// m_pHelper = SqlHelper::instance();

m_pHelper = new SqlHelper();

m_pHelper->initDB("QtWebAdmin.db");

m_mapFunc.insert("/login", &LoginController::login); //登录

m_mapFunc.insert("/logout", &LoginController::logout); //登出

}

void LoginController::service(HttpRequest& request, HttpResponse& response)

{

qDebug()<<"...................LoginController::service........................currentThreadId():"<<QThread::currentThreadId();

QByteArray path = request.getPath().toLower();

if(m_mapFunc.contains(path))

{

pServFunc func = m_mapFunc.value(path);

(this->*func)(request, response);

}

}

void LoginController::login(HttpRequest& request, HttpResponse& response)

{

qDebug()<<"..................LoginController::login...................currentThreadId():"<<QThread::currentThreadId();

ResultJson ret(0, true, QStringLiteral("登入成功"));

QString body = request.getBody();

QString username = request.getParameter("username");

QString password = request.getParameter("password");

QString vercode = request.getParameter("vercode");

QString access_token = request.getParameter("access_token");

QString codeid = request.getParameter("codeid");

HttpSession session = sessionStore->getSession(request, response, true);

if(username.isEmpty())

{

ret.failedMsg(QStringLiteral("用户名为空"));

response.write(ret.toString().toLocal8Bit());

return;

}

if(password.isEmpty())

{

ret.failedMsg(QStringLiteral("密码为空"));

response.write(ret.toString().toLocal8Bit());

return;

}

if(vercode.isEmpty())

{

ret.failedMsg(QStringLiteral("验证码为空"));

response.write(ret.toString().toLocal8Bit());

return;

}

//

// if(!session.contains("vercode"))

// {

// ret.failedMsg(QStringLiteral("未找到验证码"));

// response.write(ret.toString().toLocal8Bit());

// return;

// }

//跨域情况下,以网页请求时附带UUID,作为验证码标志

QString sessionCode = CacheApi::instance()->get(codeid + "_vercode");

if(sessionCode.isNull())

{

ret.failedMsg(QStringLiteral("未找到验证码或验证码已过期"));

response.write(ret.toString().toLocal8Bit());

return;

}

//QString sessionCode = session.get("vercode").toString();

if(sessionCode.toLower() != vercode.toLower())

{

ret.failedMsg(QStringLiteral("验证码不匹配"));

response.write(ret.toString().toLocal8Bit());

return;

}

//................检查密码

SysUser loginUser;

if(!m_pHelper->selectUserByName(loginUser, username))

{

ret.failedMsg(QStringLiteral("未找到用户或密码不正确!"));

response.write(ret.toString().toLocal8Bit());

return;

}

SysLog log("system", SysLog::LOGIN, QStringLiteral("用户登录"),

username,

QString(__FILE__),

QString(__FUNCTION__),

GlobalFunc::JsonToString(request.getParameterJson()),

request.getPeerAddress().toString(),

request.getHeader("User-Agent"),

QStringLiteral("用户成功登录"));

QString pwdAndSalt = password + loginUser.getSalt();

QString md5Pwd = QString(QCryptographicHash::hash(pwdAndSalt.toLocal8Bit(), QCryptographicHash::Md5).toHex());

if(md5Pwd != loginUser.getPassword())

{

ret.failedMsg(QStringLiteral("密码不正确!"));

response.write(ret.toString().toLocal8Bit());

log.setMemo(QStringLiteral("密码不正确!"));

m_pHelper->insertEntity(&log);

return;

}

//JWT获取,并存入缓存

QString accessToken = JwtUtil::sign(username, password);

CacheApi::instance()->insert(username + "_token", accessToken, JwtUtil::EXPIRED_TIME);

//session保存账户名和登录时间

session.set("username", username);

session.set("logintime", QTime::currentTime());

//返回token

ret.setData("access_token", accessToken);

ResponseUtil::replyJson(response, ret);

m_pHelper->insertEntity(&log);

}

// /logout?access_token=?

void LoginController::logout(HttpRequest& request, HttpResponse& response)

{

QString access_token = request.getParameter("access_token");

QString username = JwtUtil::getUsername(access_token);

CacheApi::instance()->remove(username + "_token");

QJsonObject objParam = request.getParameterJson();

objParam.insert("access_token", "?");

// ResponseUtil::replyJson(response, ResultJson(0, true, QStringLiteral("操作成功")));

SysLog log("system", SysLog::LOGOUT, QStringLiteral("用户退出"),

username,

QString(__FILE__),

QString(__FUNCTION__),

GlobalFunc::JsonToString(objParam),

request.getPeerAddress().toString(),

request.getHeader("User-Agent"),

QStringLiteral("用户退出成功"));

m_pHelper->insertEntity(&log);

}



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。