Qt6.9.1起一个图片服务器(支持前端跨域请求,不支持上传,可扩展)

ImageHttpServer.h

cpp 复制代码
#pragma once

#include <QObject>
#include <QHttpServer>
#include <QTcpServer>

class ImageHttpServer : public QObject
{
    Q_OBJECT

public:
    explicit ImageHttpServer(QObject *parent = nullptr);

    bool start(quint16 port);

private:
    void initImagesDir();
    void setupCors();
    void setupRoutes();

    static bool isIllegalPath(const QString &path);

private:
    QHttpServer m_server;
    QTcpServer  m_tcpServer;
};

ImageHttpServer.cpp

cpp 复制代码
#include "ImageHttpServer.h"

#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QMimeDatabase>
#include <QDebug>

ImageHttpServer::ImageHttpServer(QObject *parent)
    : QObject(parent)
{
    initImagesDir();
    setupCors();
    setupRoutes();
}

/*
 * 路径安全校验
 */
bool ImageHttpServer::isIllegalPath(const QString &s)
{
    return s.contains("..") || s.contains('/') || s.contains('\\');
}

/*
 * 初始化 images 目录
 */
void ImageHttpServer::initImagesDir()
{
    const QString imagesDir =
        QCoreApplication::applicationDirPath() + "/images";

    QDir dir;
    if (!dir.exists(imagesDir)) {
        qInfo() << "[初始化] images 目录不存在,正在创建...";
        if (dir.mkpath(imagesDir)) {
            qInfo() << "[初始化] images 目录创建成功:" << imagesDir;
        } else {
            qFatal("[初始化] images 目录创建失败!");
        }
    } else {
        qInfo() << "[初始化] images 目录已存在:" << imagesDir;
    }
}

/*
 * 全局 CORS 设置
 */
void ImageHttpServer::setupCors()
{
    m_server.addAfterRequestHandler(
        this,
        [](const QHttpServerRequest &,
           QHttpServerResponse &response) {

            response.headers().append(
                QByteArray("Access-Control-Allow-Origin"),
                QByteArray("*"));

            response.headers().append(
                QByteArray("Access-Control-Allow-Methods"),
                QByteArray("GET, POST, OPTIONS"));

            response.headers().append(
                QByteArray("Access-Control-Allow-Headers"),
                QByteArray("Content-Type"));

            response.headers().append(
                QByteArray("Access-Control-Allow-Credentials"),
                QByteArray("true"));
        });
}

/*
 * 路由配置
 */
void ImageHttpServer::setupRoutes()
{
    // OPTIONS 预检
    m_server.route(".*",
                   QHttpServerRequest::Method::Options,
                   []() {
                       return QHttpServerResponse(
                           QHttpServerResponse::StatusCode::NoContent);
                   });

    // 图片访问
    m_server.route("/image/<arg>/<arg>",
                   [](const QString &folder,
                      const QString &fileName) {

                       qInfo() << "[HTTP] 图片请求"
                               << folder << fileName;

                       if (isIllegalPath(folder) ||
                           isIllegalPath(fileName)) {
                           return QHttpServerResponse(
                               QHttpServerResponse::StatusCode::Forbidden);
                       }

                       const QString baseDir =
                           QCoreApplication::applicationDirPath() + "/images";
                       const QString fullPath =
                           baseDir + "/" + folder + "/" + fileName;

                       QFile file(fullPath);
                       if (!file.exists()) {
                           return QHttpServerResponse(
                               QHttpServerResponse::StatusCode::NotFound);
                       }

                       if (!file.open(QIODevice::ReadOnly)) {
                           return QHttpServerResponse(
                               QHttpServerResponse::StatusCode::InternalServerError);
                       }

                       QMimeDatabase db;
                       const QByteArray data = file.readAll();
                       const QByteArray mime =
                           db.mimeTypeForFile(fullPath).name().toUtf8();

                       return QHttpServerResponse(mime, data);
                   });
}

/*
 * 启动服务器
 */
bool ImageHttpServer::start(quint16 port)
{
    qInfo() << "[TCP] 监听 0.0.0.0:" << port;

    if (!m_tcpServer.listen(QHostAddress::Any, port)) {
        qCritical() << "[TCP] 监听失败:"
                    << m_tcpServer.errorString();
        return false;
    }

    m_server.bind(&m_tcpServer);

    qInfo() << "[HTTP] 服务启动成功";
    qInfo() << "示例:http://127.0.0.1:"
            << port << "/image/cam1/1.jpg";

    return true;
}

main.cpp

cpp 复制代码
#include <QCoreApplication>
#include <QDebug>
#include "ImageHttpServer.h"

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);

    qInfo() << "===================================";
    qInfo() << "Qt 图片 HTTP 服务器";
    qInfo() << "Qt 版本:" << QT_VERSION_STR;
    qInfo() << "程序目录:" << QCoreApplication::applicationDirPath();
    qInfo() << "===================================";

    ImageHttpServer server;
    if (!server.start(8080)) {
        return -1;
    }

    return app.exec();
}
相关推荐
REDcker1 小时前
基于 eBPF 的网络可观测:协议栈路径与 sk_buff
linux·服务器·网络·php·ebpf·bpf
孫治AllenSun1 小时前
【JVM】四大引用类型分析
java·开发语言·jvm
看-是灰机1 小时前
使用go语言实现对接
linux·开发语言·后端·docker·语言模型·golang·飞书
Urbano1 小时前
工装夹克、职业单西口袋工艺自动化改造深度解析
运维·自动化
草莓熊Lotso1 小时前
【Linux网络】深入理解Linux IO多路复用:从本质到select服务器实战
linux·运维·服务器·c语言·网络·数据库·c++
fen_fen1 小时前
麒麟 Linux aarch64安装.NET 6,并适配.net应用(达梦数据库)
linux·服务器·.net
fen_fen2 小时前
Filebeat 采集 应用日志部署 & Kibana 查询操作文档
linux·运维·服务器
草莓熊Lotso2 小时前
【LangChain】输出解析器全解:让大模型输出从 “聊天” 变 “机器可读”
服务器·数据库·python·langchain·pip
取谖慕12.2 小时前
Prometheus+Alertmanager+node_exporter+grafana高可用
linux·运维·grafana·prometheus