Qt 使用 QNetworkReply 获取外部 IP 地址
Qt get external IP address using QNetworkReply
美好的一天
简介:
我的应用程序需要获取外部 IP 地址并将其与内部获取的地址进行匹配,从而允许应用程序继续进行。
为此,我使用了 QNetworkAccessManager and QNetworkReply。
我的代码是使用 this 示例作为参考构建的。
我试过的:
获取外部 IP 可以通过从 ipify API.
获取 JSon object 来完成
我通过以下方式确认了这一点:
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 设置为 application/x-www-form-urlencoded
).
您绝对不需要模仿 Web 浏览器发送表单的请求,以便能够与 API ipify.org
提供的对话。 ipify.org
提供了一个更简单的界面;您只需要在获取请求中发送查询字符串即可。 Qt 通过提供 class 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();
}
美好的一天
简介:
我的应用程序需要获取外部 IP 地址并将其与内部获取的地址进行匹配,从而允许应用程序继续进行。
为此,我使用了 QNetworkAccessManager and QNetworkReply。
我的代码是使用 this 示例作为参考构建的。
我试过的:
获取外部 IP 可以通过从 ipify API.
获取 JSon object 来完成我通过以下方式确认了这一点:
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 设置为 application/x-www-form-urlencoded
).
您绝对不需要模仿 Web 浏览器发送表单的请求,以便能够与 API ipify.org
提供的对话。 ipify.org
提供了一个更简单的界面;您只需要在获取请求中发送查询字符串即可。 Qt 通过提供 class 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();
}