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(); 
}
Другие вопросы по тегам