c++ - Qt 使用 QNetworkReply 获取外部 IP 地址

标签 c++ json qt qnetworkaccessmanager qnetworkreply

美好的一天

简介:

我的应用程序需要获取外部 IP 地址并将其与内部获取的地址进行匹配,从而允许应用程序继续进行。

为此,我使用了 QNetworkAccessManagerQNetworkReply为此目的。

我的代码是使用 this 构建的示例作为引用。

我尝试过的:

可以通过从 ipify API 获取 JSON 对象来获取外部 IP。 .

我通过以下方式确认了这一点:

curl "https://api.ipify.org?format=json"

然后以我当前的 IP 地址响应,格式如下:

{"ip":"255.255.255.255"}

这是一个 JSonObject。使用它,我创建了下面的代码。

问题:

问题很简单,我没有得到任何回应。 post 请求已执行,但根本不会触发任何响应(或 finished)信号。

  • POST -> GET 请求

我已经更改了 get 请求的代码,因为这解决了这个无响应问题,发现于 this thread .

我通过在 URL 中指定带有查询参数的整个 url 来做到这一点:

QNetworkRequest request(QUrl("https://api.ipify.org?format=json"));

包括 header 内容类型和大小(如下例所示,最终调用 QNetworkAccessManager::get() 时:

replyExternalAddress = networkManager->get(request);

但这也没有回应。

我认为我缺少的是一些小东西,但我根本看不到它。

建议?


查询外网IP代码:

// public callable method, starting network request
void APICommunicator::requestExternalAddress(){
    qInfo(apicommunicator) << "Requesting external IP address from ipify.org";

    // creates network request
    // specifies "format=json"
    QUrlQuery postData;
    postData.addQueryItem("format", "json");
    QByteArray encodedQuery = postData.toString(QUrl::FullyEncoded).toUtf8();
    QNetworkRequest request(QUrl("https://api.ipify.org"));

    request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
    request.setHeader(QNetworkRequest::ContentLengthHeader, QString::number(encodedQuery.size()));

    // creates merged URL from URL and query items and sends a post:
    //    https://api.ipify.org?format=json
    replyExternalAddress = networkManager->post(request, encodedQuery);

    // Creates QMetaObject::Connection connection for finished signal from QNetworkReply
    conExternalAddress = QObject::connect(replyExternalAddress, SIGNAL(finished()), this, SLOT(externalAddressResponse()));

    // attach error listener to reply
    addErrorListener(replyExternalAddress, conExternalAddress);


}

void APICommunicator::externalAddressResponse(){
    qDebug(apicommunicator) << "External Address response recieved";

    // disconnect signals
    QObject::disconnect(conExternalAddress);
    QObject::disconnect(conErrorListener);

    // read all output from JSon object
    QByteArray ba = replyExternalAddress->readAll();

    // delete QNetworkReply
    replyExternalAddress->deleteLater();

    LogMessageHandler::writeToApiLog(QString("\n\nCALL EXTERNAL [" + replyExternalAddress->request().url().toString() + "]\n" + QString(ba)));

    QJsonObject doc = QJsonDocument::fromJson(ba).object();
    QString ip = doc.value("ip").toString();    
    QHostAddress address = QHostAddress();

    if (ip.isEmpty()) {
        qWarning(apicommunicator) << "External Address: no data received";
    }
    else {
        address = QHostAddress(version);
    }

    // replies with address to external slot (in main application)
    emit ExternalAddressReply(address);
}

最佳答案

问题是您发送的是 POST 请求,而 ipify.org 只需要 GET 请求。您似乎误以为您需要发送 POST 请求才能随请求一起发送参数 (format=json),这不是真的。在您的代码中,您将参数作为 POST 数据发送,这与您在浏览器中提交 Web 表单时使用的技术相同(因为您将内容类型 header 设置为 应用程序/x-www-form-urlencoded).

您绝对不需要模仿 Web 浏览器发送表单的请求,以便能够与 ipify.org 提供的 API 对话。 ipify.org 提供了一个更简单的界面;您只需要在获取请求中发送查询字符串即可。 Qt 通过提供类 QUrlQuery 使工作变得更加容易它提供了一种构建 url 查询的方法。这是一个工作示例:

#include <QtCore>
#include <QtNetwork>

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

    QNetworkAccessManager networkManager;

    QUrl url("https://api.ipify.org");
    //the query used to add the parameter "format=json" to the request
    QUrlQuery query;
    query.addQueryItem("format", "json");
    //set the query on the url
    url.setQuery(query);

    //make a *get* request using the above url
    QNetworkReply* reply = networkManager.get(QNetworkRequest(url));

    QObject::connect(reply, &QNetworkReply::finished,
                     [&](){
        if(reply->error() != QNetworkReply::NoError) {
            //failure
            qDebug() << "error: " << reply->error();
        } else { //success
            //parse the json reply to extract the IP address
            QJsonObject jsonObject= QJsonDocument::fromJson(reply->readAll()).object();
            QHostAddress ip(jsonObject["ip"].toString());
            //do whatever you want with the ip
            qDebug() << "external ip: " << ip;
        }
        //delete reply later to prevent memory leak
        reply->deleteLater();
        a.quit();
    });
    return a.exec(); 
}

关于c++ - Qt 使用 QNetworkReply 获取外部 IP 地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47844479/

相关文章:

c# - 使用 JSON.net 和 .net WebApi 反序列化 TimeSpan

qt - 启用自动换行时,qlabel 的 sizeHint() 错误

qt - 拥有诺基亚 Qt 技术支持的经验吗?

c++ - 从 Qt Linux 应用程序连接到 MS SQLServer

c++ - 如何判断算法是否有效?

c# - 使用 EF4 的循环引用

c++ - N阶乘有多少位数

c# - Web api 在序列化从 DynamicObject 继承的对象时忽略原始属性

c++ - 本身复制 vector

c++ - 如何从Makefile中识别冗余库?有没有什么工具可以分析库的使用情况?