我一直在尝试调整一个用于从服务器下载单个文件的小型Qt程序。所有它(现在)都要求提供一个URL,然后下载它。
在进行更复杂的操作之前,我想要做的是让它与身份验证一起使用。在阅读文档并找到一些涉及QNetworkAccessManager和QAuthenticator类的示例后,我尝试修改它。但由于某种原因,当我正确地将来自我的QNetworkAccessManager实例的authenticationRequired信号链接到自定义插槽并将用户名/密码设置为QAuthenticator对象时,似乎永远不会发送authenticationRequired信号(将qDebug放入插槽中。用户名和密码现在是硬编码的(我计划稍后在我开始工作时加入)。
我验证了我在调用get()之前放了connect()并尝试了几个地方:我尝试的第一件事就是将QNetworkAccessManager创建放在我的类'构造函数中,然后才使用get()。但似乎没有任何工作,因为我在尝试下载需要auth时获得的是“禁止”错误代码。因为我之前从未使用过Qt Network课程,所以我不确定在哪里发现我做错了什么。
这是我的完整代码
//HttpDownload.h
#ifndef HTTPDOWNLOAD_H
#define HTTPDOWNLOAD_H
#include <QDialog>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QProgressDialog>
#include <QFile>
#include <QFileInfo>
#include <QDir>
#include <QMessageBox>
#include <QDebug>
#include <QAuthenticator>
namespace Ui {
class HttpDownload;
}
class HttpDownload : public QDialog
{
Q_OBJECT
public:
explicit HttpDownload(QWidget *parent = 0);
~HttpDownload();
public:
void startRequest(QUrl url);
private slots:
void on_downloadButton_clicked();
void on_quitButton_clicked();
void on_urlEdit_returnPressed();
// slot for readyRead() signal
void httpReadyRead();
// slot for finished() signal from reply
void httpDownloadFinished();
// slot for downloadProgress()
void updateDownloadProgress(qint64, qint64);
void enableDownloadButton();
void cancelDownload();
void authRequired(QNetworkReply*, QAuthenticator*); // Auth slot
private:
Ui::HttpDownload *ui;
QUrl url;
QNetworkAccessManager *manager;
QNetworkReply *reply;
QProgressDialog *progressDialog;
QFile *file;
bool httpRequestAborted;
qint64 fileSize;
};
#endif // HTTPDOWNLOAD_H
//HttpDownload.cpp
#include "httpdownload.h"
#include "ui_httpdownload.h"
HttpDownload::HttpDownload(QWidget *parent) :
QDialog(parent),
ui(new Ui::HttpDownload)
{
ui->setupUi(this);
ui->urlEdit->setText(HTTPS_URL);
ui->statusLabel->setWordWrap(true);
ui->downloadButton->setDefault(true);
ui->quitButton->setAutoDefault(false);
progressDialog = new QProgressDialog(this);
connect(ui->urlEdit,
SIGNAL(textChanged(QString)),
this,
SLOT(enableDownloadButton())
);
connect(progressDialog,
SIGNAL(canceled()),
this,
SLOT(cancelDownload())
);
}
HttpDownload::~HttpDownload()
{
delete ui;
}
// Auth slot
void HttpDownload::authRequired(QNetworkReply *reply, QAuthenticator *ator)
{
qDebug() << "auth Alert";
qDebug() << reply->readAll(); // this is just to see what we received
qDebug() << Q_FUNC_INFO << ator->realm();
ator->setUser(QString(USERNAME));
ator->setPassword(QString(PASSWORD));
}
void HttpDownload::on_downloadButton_clicked()
{
// manager = new QNetworkAccessManager(this);
// get url
url = (ui->urlEdit->text());
QFileInfo fileInfo(url.path());
QString fileName = fileInfo.fileName();
if (fileName.isEmpty())
fileName = "index.html";
if (QFile::exists(fileName)) {
if (QMessageBox::question(this, tr("HTTP"),
tr("There already exists a file called %1 in "
"the current directory. Overwrite?").arg(fileName),
QMessageBox::Yes|QMessageBox::No, QMessageBox::No)
== QMessageBox::No)
return;
QFile::remove(fileName);
}
file = new QFile(fileName);
if (!file->open(QIODevice::WriteOnly)) {
QMessageBox::information(this, tr("HTTP"),
tr("Unable to save the file %1: %2.")
.arg(fileName).arg(file->errorString()));
delete file;
file = 0;
return;
}
// used for progressDialog
// This will be set true when canceled from progress dialog
httpRequestAborted = false;
progressDialog->setWindowTitle(tr("HTTP"));
progressDialog->setLabelText(tr("Downloading %1.").arg(fileName));
// download button disabled after requesting download
ui->downloadButton->setEnabled(false);
startRequest(url);
}
void HttpDownload::httpReadyRead()
{
// this slot gets called every time the QNetworkReply has new data.
// We read all of its new data and write it into the file.
// That way we use less RAM than when reading it at the finished()
// signal of the QNetworkReply
if (file)
file->write(reply->readAll());
}
void HttpDownload::updateDownloadProgress(qint64 bytesRead, qint64 totalBytes)
{
if (httpRequestAborted)
return;
progressDialog->setMaximum(totalBytes);
progressDialog->setValue(bytesRead);
}
void HttpDownload::on_quitButton_clicked()
{
this->close();
}
void HttpDownload::on_urlEdit_returnPressed()
{
on_downloadButton_clicked();
}
void HttpDownload::enableDownloadButton()
{
ui->downloadButton->setEnabled(!(ui->urlEdit->text()).isEmpty());
}
// During the download progress, it can be canceled
void HttpDownload::cancelDownload()
{
ui->statusLabel->setText(tr("Download canceled."));
httpRequestAborted = true;
reply->abort();
ui->downloadButton->setEnabled(true);
}
// When download finished or canceled, this will be called
void HttpDownload::httpDownloadFinished()
{
// when canceled
if (httpRequestAborted) {
if (file) {
file->close();
file->remove();
delete file;
file = 0;
}
reply->deleteLater();
progressDialog->hide();
return;
}
// download finished normally
progressDialog->hide();
file->flush();
file->close();
// get redirection url
QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
if (reply->error()) {
file->remove();
QMessageBox::information(this, tr("HTTP"),
tr("Download failed: %1.")
.arg(reply->errorString()));
ui->downloadButton->setEnabled(true);
} else if (!redirectionTarget.isNull()) {
QUrl newUrl = url.resolved(redirectionTarget.toUrl());
if (QMessageBox::question(this, tr("HTTP"),
tr("Redirect to %1 ?").arg(newUrl.toString()),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
url = newUrl;
reply->deleteLater();
file->open(QIODevice::WriteOnly);
file->resize(0);
startRequest(url);
return;
}
} else {
QString fileName = QFileInfo(QUrl(ui->urlEdit->text()).path()).fileName();
ui->statusLabel->setText(tr("Downloaded %1 to %2.").arg(fileName).arg(QDir::currentPath()));
ui->downloadButton->setEnabled(true);
}
reply->deleteLater();
reply = 0;
delete file;
file = 0;
manager = 0;
}
// This will be called when download button is clicked
void HttpDownload::startRequest(QUrl url)
{
qDebug() << "Begin download";
manager = new QNetworkAccessManager(this);
connect(manager,
SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
SLOT(authRequired(QNetworkReply*,QAuthenticator*))
);
// get() method posts a request
// to obtain the contents of the target request
// and returns a new QNetworkReply object
// opened for reading which emits
// the readyRead() signal whenever new data arrives.
reply = manager->get(QNetworkRequest(url));
// Whenever more data is received from the network,
// this readyRead() signal is emitted
connect(reply, SIGNAL(readyRead()),
this, SLOT(httpReadyRead()));
// Also, downloadProgress() signal is emitted when data is received
connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
this, SLOT(updateDownloadProgress(qint64,qint64)));
// This signal is emitted when the reply has finished processing.
// After this signal is emitted,
// there will be no more updates to the reply's data or metadata.
connect(reply, SIGNAL(finished()),
this, SLOT(httpDownloadFinished()));
}
//main.cpp
#include "httpdownload.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
HttpDownload w;
w.setWindowTitle("Http Download");
w.show();
return a.exec();
}
答案 0 :(得分:-1)
连接将来会发生的接听电话。在任何可能触发它们的调用之前,您应该完成所有连接。之后,如果auth事件永远不会发生,则表示主机是问题,而不是代码。您的auth方法看起来是正确的。尝试使用Fiddler或类似的东西进行追踪。
答案 1 :(得分:-1)
我认为您在SLOT之前错过了 this !
connect(manager,
SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
SLOT(authRequired(QNetworkReply*,QAuthenticator*))
);
应该是
connect(manager,
SIGNAL(authenticationRequired(QNetworkReply*,QAuthenticator*)),
this, SLOT(authRequired(QNetworkReply*,QAuthenticator*))
);