You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

QT5 Windows应用获取系统代理例外列表及适配问题

解决方案:Windows下Qt5适配系统代理例外列表

我之前也遇到过类似的问题,折腾了好一阵才搞定,下面是具体的解决思路和代码示例:

一、能不能获取系统代理例外列表?

当然可以!Windows的IE/系统代理设置(包括例外列表)并没有被Qt直接封装,但我们可以通过Windows原生WinINet API来获取。

具体来说,使用WinHttpGetIEProxyConfigForCurrentUser函数就能拿到包含例外列表的结构体。以下是可直接复用的代码:

#include <windows.h>
#include <winhttp.h>
#include <QString>
#include <QDebug>

#pragma comment(lib, "winhttp.lib")

QString getSystemProxyBypassList() {
    WINHTTP_CURRENT_USER_IE_PROXY_CONFIG proxyConfig;
    ZeroMemory(&proxyConfig, sizeof(proxyConfig));

    // 获取当前用户的IE代理配置
    if (WinHttpGetIEProxyConfigForCurrentUser(&proxyConfig)) {
        if (proxyConfig.lpszProxyBypass != nullptr) {
            QString bypassList = QString::fromWCharArray(proxyConfig.lpszProxyBypass);
            // 记得释放API分配的堆内存,避免泄漏
            GlobalFree(proxyConfig.lpszProxyBypass);
            if (proxyConfig.lpszProxy) GlobalFree(proxyConfig.lpszProxy);
            return bypassList;
        }
    } else {
        qDebug() << "获取代理配置失败,错误码:" << GetLastError();
    }
    return "";
}

这个函数会返回和Internet选项里完全一致的例外列表字符串,比如"<local>;*.example.com;192.168.*"

二、能不能让例外列表在Qt应用中生效?

Qt的QNetworkProxy本身不支持自动匹配例外规则,但我们可以通过自定义QNetworkProxyFactory来实现这个逻辑——核心就是拦截每个网络请求,判断目标URL是否在例外列表里,是就走直连,否则用代理。

步骤1:实现自定义代理工厂

#include <QNetworkProxyFactory>
#include <QNetworkProxy>
#include <QUrl>
#include <QStringList>
#include <QRegExp>

class SystemProxyFactory : public QNetworkProxyFactory {
public:
    SystemProxyFactory(const QString& bypassList, const QNetworkProxy& proxy)
        : m_bypassList(bypassList.split(';', Qt::SkipEmptyParts)),
          m_proxy(proxy) {}

    QList<QNetworkProxy> queryProxy(const QNetworkProxyQuery& query) override {
        QUrl targetUrl = query.url();
        QString targetHost = targetUrl.host();

        // 遍历例外规则,匹配则走直连
        for (const QString& rule : m_bypassList) {
            if (matchBypassRule(targetHost, rule.trimmed())) {
                return {QNetworkProxy::NoProxy};
            }
        }

        // 不匹配例外则用指定代理
        return {m_proxy};
    }

private:
    bool matchBypassRule(const QString& host, const QString& rule) {
        // 处理<local>规则:匹配本地主机名(无点)或私有IP段
        if (rule == "<local>") {
            return !host.contains('.') || 
                   host.startsWith("127.") || 
                   host.startsWith("192.168.") || 
                   host.startsWith("10.") || 
                   host.startsWith("172.16.");
        }

        // 处理通配符规则,比如*.example.com
        QString pattern = rule.replace("*", ".*");
        QRegExp regExp(pattern, Qt::CaseInsensitive);
        return regExp.exactMatch(host);
    }

    QStringList m_bypassList;
    QNetworkProxy m_proxy;
};

步骤2:全局注册生效

在应用初始化的地方,获取例外列表、创建工厂并设置为全局代理工厂:

#include <QApplication>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    // 1. 获取系统代理例外列表
    QString bypassList = getSystemProxyBypassList();

    // 2. 初始化你的HTTP代理
    QNetworkProxy proxy;
    proxy.setType(QNetworkProxy::HttpProxy);
    proxy.setHostName("你的代理主机");
    proxy.setPort(你的代理端口);

    // 3. 设置自定义代理工厂(注意:工厂会被Qt自动管理内存,无需手动delete)
    SystemProxyFactory* factory = new SystemProxyFactory(bypassList, proxy);
    QNetworkProxyFactory::setApplicationProxyFactory(factory);

    // 后续应用代码...

    return a.exec();
}

额外提醒

  • 如果需要支持更复杂的例外规则(比如精确IP段匹配),可以扩展matchBypassRule函数的逻辑。
  • 要是系统代理设置动态变化,你可以监听注册表HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings的变化,实时更新例外列表。

内容的提问来源于stack exchange,提问作者OzanYukruk

火山引擎 最新活动