Qt получить внешний IP-адрес, используя QNetworkReply
Добрый день
Вступление:
Мое приложение требует получения внешнего IP-адреса и сопоставления его с внутренним полученным адресом, что позволяет приложению продолжить работу.
Для этого я использую QNetworkAccessManager и QNetworkReply для этой цели.
Мой код был построен с использованием этого примера в качестве ссылки.
Что я пробовал:
Получение внешнего IP-адреса может быть выполнено путем получения объекта JSon из API ipify.
Я подтвердил это:
curl "https://api.ipify.org?format=json"
который в свою очередь отвечает моим текущим IP-адресом в формате:
{"ip":"255.255.255.255"}
который является JSonObject. Используя это, я создал код ниже.
Проблема:
Проблема довольно проста, я не получаю ответа. post
запрос выполнен, но просто нет ответа (или finished
) сигнал срабатывает.
POST
->GET
запрос
Я изменил код для get
запрос, как это решило эту проблему без ответа, найден в этой теме.
Я сделал это, указав весь URL с параметрами запроса в URL:
QNetworkRequest request(QUrl("https://api.ipify.org?format=json"));
включая тип и размер содержимого заголовка (как в примере ниже, наконец, вызывая 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);
}
1 ответ
Проблема в том, что вы отправляете POST
запрос, пока ipify.org
ожидает только GET
Запросы. Кажется, у вас неправильное представление о том, что вам нужно POST
запрос для возможности отправки параметров (format=json
) вместе с вашей просьбой это не так. В своем коде вы отправляете параметры как POST
данные, это тот же метод, который используется при отправке веб-формы в браузере (поскольку вы устанавливаете заголовок типа контента на application/x-www-form-urlencoded
).
Вам абсолютно не нужно имитировать запрос веб-браузера, отправляющего форму, чтобы иметь возможность общаться с API ipify.org
обеспечивает. ipify.org
обеспечивает гораздо более простой интерфейс; вам просто нужно отправить строку запроса в вашем запросе get. 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();
}