在 Qt 应用程序中共享 cookie 的最佳方式

Best way to share cookies within Qt application

我可以使用 QNetworkCookieJar 检索、存储和重新发送 QNetworkManager 的 cookie。多个 QNetworkAccessManager 个实例可以共享一个 QNetworkCookieJar.

到目前为止,我已经使用了多个 QNetworkAccessManager 个实例,每个 class 个实例(我需要阅读的地方):

  1. 所以我可以在 1..n QNetworkAccessManager 个实例之间共享一个单例 QNetworkCookieJar
  2. 或者只有一个单例 QNetworkAccessManager 和一个 Jar 在所有 QNetworkRequest 之间共享是否更好。 QNetworkAccessManager 作为单个对象是可行的方法吗?文档说应该只有一个实例。那么我最好使用单例 QNetworkAccessManager?

最合适的方式是什么?

------ 编辑 ------

据我所知,

是正确的。这也是文档所说的。但是,在尝试这种方法时,我注意到了两个问题:

  1. 虽然我们现在每个 Web 服务有一个 QNetworkAccessManager,但更改为一个实例意味着我需要始终区分我刚刚在“完成”槽中收到的内容类型(从 QNetworkAccessManager::finished).可行,但不方便。
  2. 我们 运行 我们的读者在不同的线程中 - 不幸的是我忘了在问题中提到这一点。这使得几乎不可能使用 QNetworkAccessManager 的单个实例,因为成员函数是 reentrant, but not thread safe. ( QNetworkAccessManager from ThreadPool )

相关:

我假设您指的是 QNetworkAccessManager,而不是 QNetworkManager

您应该更喜欢在您的应用程序中使用一个 QNetworkAccessManager。这不仅消除了同步 QNetworkCookieJar 的任何需要,而且确保网络得到最佳利用,并且缓存内容等得到共享。

正如您自己注意到的,QtNetworkAccessManager 中也暗示了这一点 documentation

One QNetworkAccessManager should be enough for the whole Qt application.

这是我所做的(并且似乎有效):

  1. 当我们在线程中阅读时,我无法使用单个 QNetworkAccessManager
  2. 共享 QNetworkCookieJar 不是一个选项,因为它不是线程安全的

但是创建我自己的微型线程安全 - 源自 QNetworkCookieJar - class 很容易。我只需要担心 5 个虚函数。我可以在 QNetworkAccessManager 之间共享这个线程安全的 cookie 罐。

我 运行 这里有一定的风险,因为 QObject 的其他 public 成员函数不是线程安全的,可能会崩溃,但这些似乎并没有在那个用途中被利用案例.

请求的示例代码:

/*!
 * Cookie manager, which allows thread safe sharing of cookies
 */
class BLACKCORE_EXPORT CCookieManager : public QNetworkCookieJar
{
    Q_OBJECT

public:
    //! Constructor, only allowed from BlackCore::CApplication
    CCookieManager(BlackMisc::Restricted<CApplication>, QObject *parent = nullptr);

    //! \copydoc QNetworkCookieJar::setCookiesFromUrl
    //! \threadsafe
    virtual bool setCookiesFromUrl(const QList<QNetworkCookie> &cookies, const QUrl &url) override;

    //! \copydoc QNetworkCookieJar::cookiesForUrl
    //! \threadsafe
    virtual QList<QNetworkCookie> cookiesForUrl(const QUrl &url) const override;

    //! Cookies for request
    //! \threadsafe
    QList<QNetworkCookie> cookiesForRequest(const QNetworkRequest &request) const;

    //! \copydoc QNetworkCookieJar::deleteCookie
    //! \threadsafe
    virtual bool deleteCookie(const QNetworkCookie &cookie) override;

    //! Delete all cookies
    //! \threadsafe
    void deleteAllCookies();

    //! \copydoc QNetworkCookieJar::insertCookie
    //! \threadsafe
    virtual bool insertCookie(const QNetworkCookie &cookie) override;

    //! \copydoc QNetworkCookieJar::updateCookie
    //! \threadsafe
    virtual bool updateCookie(const QNetworkCookie &cookie) override;

private:
    mutable QReadWriteLock m_lock { QReadWriteLock::Recursive };
};

CCookieManager::CCookieManager(BlackMisc::Restricted<CApplication>, QObject *parent) : QNetworkCookieJar(parent)
{
    // code
}

bool CCookieManager::setCookiesFromUrl(const QList<QNetworkCookie> &cookies, const QUrl &url)
{
    QWriteLocker l(&m_lock);
    return QNetworkCookieJar::setCookiesFromUrl(cookies, url);
}

QList<QNetworkCookie> CCookieManager::cookiesForUrl(const QUrl &url) const
{
    QReadLocker l(&m_lock);
    const QList<QNetworkCookie> cookies(QNetworkCookieJar::cookiesForUrl(url));
    return cookies;
}

QList<QNetworkCookie> CCookieManager::cookiesForRequest(const QNetworkRequest &request) const
{
    return cookiesForUrl(request.url());
}

bool CCookieManager::deleteCookie(const QNetworkCookie &cookie)
{
    QWriteLocker l(&m_lock);
    return QNetworkCookieJar::deleteCookie(cookie);
}

bool CCookieManager::insertCookie(const QNetworkCookie &cookie)
{
    QWriteLocker l(&m_lock);
    return QNetworkCookieJar::insertCookie(cookie);
}

bool CCookieManager::updateCookie(const QNetworkCookie &cookie)
{
    QWriteLocker l(&m_lock);
    return QNetworkCookieJar::updateCookie(cookie);
}

void CCookieManager::deleteAllCookies()
{
    QWriteLocker l(&m_lock);
    this->setAllCookies(QList<QNetworkCookie>());
}