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();
}
相关推荐
生活很暖很治愈19 小时前
Linux——线程互斥,互斥锁
linux·运维·服务器
锅包一切19 小时前
一、C++ 发展与程序创建
开发语言·c++·后端·学习·编程
小李独爱秋19 小时前
模拟面试:说一下数据库主从不同步的原因。
运维·服务器·mysql·面试·职场和发展·性能优化
tryCbest19 小时前
Linux常用命令V2026
linux·运维
一株菌子19 小时前
10.12 总结
开发语言·python
power 雀儿20 小时前
LibTorch激活函数&LayerNorm归一化
c++·人工智能
枷锁—sha20 小时前
【CTFshow-pwn系列】03_栈溢出【pwn 051】详解:C++字符串替换引发的血案与 Ret2Text
开发语言·网络·c++·笔记·安全·网络安全
沙白猿20 小时前
【TJXT】Day3
java·开发语言
一个处女座的程序猿O(∩_∩)O20 小时前
Python面向对象的封装特性详解
开发语言·python
zhaoyin199420 小时前
python基础
开发语言·python