使用 post 请求将文件块上传到服务器。 Qt6 QNetworkAccessManager post。数据未到
Uploading chunk of file to server with post request. Qt6 QNetworkAccessManager post. Data not arrieved
我正在尝试移植我的程序 (python(PyQt6) >> C++(Qt6))
在 python 我有这个:
requests.post(f"{self.server}/uploadChunk/{self.rnum}?" + urlencode(
{"index": cnum, "findex": findex, "token": self.token, "Hash": out_hash}),
data=chunk, verify=False)
我正在尝试将它移植到 C++ 并得到这个:
void Tunnel::sendChunk(quint64 findex, quint64 index, QByteArray chunk, QString hash) {
qDebug() << "T: sendChunk";
TunnelWorker *worker = (TunnelWorker*)this->sender();
quint64 id = worker->Id;
QNetworkAccessManager *manager = (*this->Managers)[id][1];
QString url = this->server + "/uploadChunk/" + QString::number(this->rnum) + "?token=" + this->token;
if ((int)index != -1) {
url += "&findex=" + QString::number(findex) + "&index=" + QString::number(index) + "&hash=" + hash;
}
QNetworkRequest req = QNetworkRequest(url);
req.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data");
QNetworkReply *reply = manager->post(req, chunk);
QObject::connect(reply, &QNetworkReply::uploadProgress, worker, &TunnelWorker::sendChunkProgressHandler);
}
在控制台中,我看到文件正在上传:
TW: sendChunkProgressHandler
T: addUploadProgress "16384"
TW: sendChunkProgressHandler
T: addUploadProgress "2080768"
TW: sendChunkProgressHandler
TW: sendChunkReplyHandler: chunk uploaded
T: addUploadProgress "0"
:我的 Chunksize 是 2MiB,(2**21 Bytes),我看到所有 2MiB 都上传了。
我的服务器在 Flask 上:
class Tunnel:
...
def downloadchunk(self, data, json):
print('-' * 20)
print(f"DATA: {len(data)}")
print('-' * 20)
...
...
# end of class Tunnel
...
@app.route("/uploadChunk/<int:rnum>", methods=['GET', 'POST'])
def upload_chunk(rnum):
json = request.args
token = "00000000" if "token" not in json else json["token"]
if checkToken(rnum, "Up", token):
rnums[rnum].activity()
data = request.data
return rnums[rnum].downloadchunk(data, json)
else:
return {"status": "Access denied"}
...
如果我正在尝试我的 C++ 代码,我会在我的烧瓶服务器的 python 控制台中得到这个:
--------------------
DATA: 0
--------------------
如果我正在尝试我的 python 代码,我会得到这个...:[=25=]
--------------------
DATA: 2097152
--------------------
我需要在我的 C++ 代码中修复上传问题吗?
UDP 最小可重现示例:
main.cpp
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QNetworkAccessManager>
#include <QNetworkReply>
int main(int argc, char *argv[])
{
quint64 Kb = 1024;
quint64 Mb = 1024 * Kb;
QCoreApplication a(argc, argv);
QFile file("img.png");
file.open(QFile::ReadOnly);
QByteArray chunk = file.read(2 * Mb);
qDebug() << "Chunk:" << chunk.length();
QNetworkAccessManager *manager = new QNetworkAccessManager();
QUrl url = QUrl("http://127.0.0.1:5000/");
QNetworkRequest req = QNetworkRequest(url);
req.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data");
qDebug() << "Url:" << url.url();
QObject::connect(manager, &QNetworkAccessManager::finished, [](QNetworkReply *reply) {qDebug() << "Uploading Finish";});
QNetworkReply *reply = manager->post(req, chunk);
QObject::connect(reply, &QNetworkReply::uploadProgress, [](quint64 uploaded, quint64 total) {qDebug() << "Uploading" << QString::number(uploaded) << "/" << QString::number(total);});
return a.exec();
}
test.pro:
QT -= gui
QT += core
QT += network
CONFIG += c++17 console
CONFIG -= app_bundle
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
server.py:
from flask import Flask, request
app = Flask(__name__)
@app.route("/", methods=["GET", "POST"])
def fun():
print("DATA:", len(request.data))
return {}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
UDP2:
我的控制台输出(C++):
Chunk: 2097152
Url: "http://127.0.0.1:5000/"
Uploading "16384" / "2097152"
Uploading "2097152" / "2097152"
Uploading "0" / "0"
Uploading Finish
我的控制台输出(Python):
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
* Serving Flask app 'SOF.py' (lazy loading)
* Environment: development
* Debug mode: off
127.0.0.1 - - [17/May/2022 15:13:02] "POST / HTTP/1.1" 200 -
DATA: 0
UDP3:
test.py
import requests
with open("img.png", "rb") as f:
data = f.read(2*1024*1024)
requests.post("http://127.0.0.1:5000/", data=data)
server.py(输出):
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
* Serving Flask app 'SOF.py' (lazy loading)
* Environment: development
* Debug mode: off
127.0.0.1 - - [17/May/2022 15:31:01] "POST / HTTP/1.1" 200 -
DATA: 2097152
问题是您表示 content-type 是 application/x-www-form-urlencoded(相当于 multipart/form-data)但您发送的不是表单而是原始数据,因此服务器会尝试解码数据但它不符合标准所以它 returns 0 字节。解决办法是使用一个有效的content-type,例如application/octet-stream,你也可以使用QMimeDatabase来获取content-type:
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QMimeDatabase>
#include <QMimeType>
int main(int argc, char *argv[])
{
quint64 Kb = 1024;
quint64 Mb = 1024 * Kb;
QCoreApplication a(argc, argv);
QFile file("img.png");
if(!file.open(QFile::ReadOnly)){
qDebug() << "failed";
return EXIT_FAILURE;
}
QByteArray chunk = file.read(2 * Mb);
qDebug() << "Chunk:" << chunk.length();
QNetworkAccessManager manager;
QUrl url = QUrl("http://127.0.0.1:5000/");
QMimeDatabase db;
QMimeType mime = db.mimeTypeForData(&file);
QNetworkRequest req(url);
req.setHeader(QNetworkRequest::ContentTypeHeader, mime.name());
// OR
// req.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");
qDebug() << "Url:" << req.url();
QObject::connect(&manager, &QNetworkAccessManager::finished, [](QNetworkReply * /*reply*/) {
qDebug() << "Uploading Finish";
QCoreApplication::quit();
});
QNetworkReply *reply = manager.post(req, chunk);
QObject::connect(reply, &QNetworkReply::uploadProgress, [](quint64 uploaded, quint64 total) {
qDebug() << "Uploading" << QString::number(uploaded) << "/" << QString::number(total);
});
return a.exec();
}
我正在尝试移植我的程序 (python(PyQt6) >> C++(Qt6)) 在 python 我有这个:
requests.post(f"{self.server}/uploadChunk/{self.rnum}?" + urlencode(
{"index": cnum, "findex": findex, "token": self.token, "Hash": out_hash}),
data=chunk, verify=False)
我正在尝试将它移植到 C++ 并得到这个:
void Tunnel::sendChunk(quint64 findex, quint64 index, QByteArray chunk, QString hash) {
qDebug() << "T: sendChunk";
TunnelWorker *worker = (TunnelWorker*)this->sender();
quint64 id = worker->Id;
QNetworkAccessManager *manager = (*this->Managers)[id][1];
QString url = this->server + "/uploadChunk/" + QString::number(this->rnum) + "?token=" + this->token;
if ((int)index != -1) {
url += "&findex=" + QString::number(findex) + "&index=" + QString::number(index) + "&hash=" + hash;
}
QNetworkRequest req = QNetworkRequest(url);
req.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data");
QNetworkReply *reply = manager->post(req, chunk);
QObject::connect(reply, &QNetworkReply::uploadProgress, worker, &TunnelWorker::sendChunkProgressHandler);
}
在控制台中,我看到文件正在上传:
TW: sendChunkProgressHandler
T: addUploadProgress "16384"
TW: sendChunkProgressHandler
T: addUploadProgress "2080768"
TW: sendChunkProgressHandler
TW: sendChunkReplyHandler: chunk uploaded
T: addUploadProgress "0"
:我的 Chunksize 是 2MiB,(2**21 Bytes),我看到所有 2MiB 都上传了。 我的服务器在 Flask 上:
class Tunnel:
...
def downloadchunk(self, data, json):
print('-' * 20)
print(f"DATA: {len(data)}")
print('-' * 20)
...
...
# end of class Tunnel
...
@app.route("/uploadChunk/<int:rnum>", methods=['GET', 'POST'])
def upload_chunk(rnum):
json = request.args
token = "00000000" if "token" not in json else json["token"]
if checkToken(rnum, "Up", token):
rnums[rnum].activity()
data = request.data
return rnums[rnum].downloadchunk(data, json)
else:
return {"status": "Access denied"}
...
如果我正在尝试我的 C++ 代码,我会在我的烧瓶服务器的 python 控制台中得到这个:
--------------------
DATA: 0
--------------------
如果我正在尝试我的 python 代码,我会得到这个...:[=25=]
--------------------
DATA: 2097152
--------------------
我需要在我的 C++ 代码中修复上传问题吗?
UDP 最小可重现示例: main.cpp
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QNetworkAccessManager>
#include <QNetworkReply>
int main(int argc, char *argv[])
{
quint64 Kb = 1024;
quint64 Mb = 1024 * Kb;
QCoreApplication a(argc, argv);
QFile file("img.png");
file.open(QFile::ReadOnly);
QByteArray chunk = file.read(2 * Mb);
qDebug() << "Chunk:" << chunk.length();
QNetworkAccessManager *manager = new QNetworkAccessManager();
QUrl url = QUrl("http://127.0.0.1:5000/");
QNetworkRequest req = QNetworkRequest(url);
req.setHeader(QNetworkRequest::ContentTypeHeader, "multipart/form-data");
qDebug() << "Url:" << url.url();
QObject::connect(manager, &QNetworkAccessManager::finished, [](QNetworkReply *reply) {qDebug() << "Uploading Finish";});
QNetworkReply *reply = manager->post(req, chunk);
QObject::connect(reply, &QNetworkReply::uploadProgress, [](quint64 uploaded, quint64 total) {qDebug() << "Uploading" << QString::number(uploaded) << "/" << QString::number(total);});
return a.exec();
}
test.pro:
QT -= gui
QT += core
QT += network
CONFIG += c++17 console
CONFIG -= app_bundle
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
server.py:
from flask import Flask, request
app = Flask(__name__)
@app.route("/", methods=["GET", "POST"])
def fun():
print("DATA:", len(request.data))
return {}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
UDP2: 我的控制台输出(C++):
Chunk: 2097152
Url: "http://127.0.0.1:5000/"
Uploading "16384" / "2097152"
Uploading "2097152" / "2097152"
Uploading "0" / "0"
Uploading Finish
我的控制台输出(Python):
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
* Serving Flask app 'SOF.py' (lazy loading)
* Environment: development
* Debug mode: off
127.0.0.1 - - [17/May/2022 15:13:02] "POST / HTTP/1.1" 200 -
DATA: 0
UDP3: test.py
import requests
with open("img.png", "rb") as f:
data = f.read(2*1024*1024)
requests.post("http://127.0.0.1:5000/", data=data)
server.py(输出):
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
* Serving Flask app 'SOF.py' (lazy loading)
* Environment: development
* Debug mode: off
127.0.0.1 - - [17/May/2022 15:31:01] "POST / HTTP/1.1" 200 -
DATA: 2097152
问题是您表示 content-type 是 application/x-www-form-urlencoded(相当于 multipart/form-data)但您发送的不是表单而是原始数据,因此服务器会尝试解码数据但它不符合标准所以它 returns 0 字节。解决办法是使用一个有效的content-type,例如application/octet-stream,你也可以使用QMimeDatabase来获取content-type:
#include <QCoreApplication>
#include <QDebug>
#include <QFile>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QMimeDatabase>
#include <QMimeType>
int main(int argc, char *argv[])
{
quint64 Kb = 1024;
quint64 Mb = 1024 * Kb;
QCoreApplication a(argc, argv);
QFile file("img.png");
if(!file.open(QFile::ReadOnly)){
qDebug() << "failed";
return EXIT_FAILURE;
}
QByteArray chunk = file.read(2 * Mb);
qDebug() << "Chunk:" << chunk.length();
QNetworkAccessManager manager;
QUrl url = QUrl("http://127.0.0.1:5000/");
QMimeDatabase db;
QMimeType mime = db.mimeTypeForData(&file);
QNetworkRequest req(url);
req.setHeader(QNetworkRequest::ContentTypeHeader, mime.name());
// OR
// req.setHeader(QNetworkRequest::ContentTypeHeader, "application/octet-stream");
qDebug() << "Url:" << req.url();
QObject::connect(&manager, &QNetworkAccessManager::finished, [](QNetworkReply * /*reply*/) {
qDebug() << "Uploading Finish";
QCoreApplication::quit();
});
QNetworkReply *reply = manager.post(req, chunk);
QObject::connect(reply, &QNetworkReply::uploadProgress, [](quint64 uploaded, quint64 total) {
qDebug() << "Uploading" << QString::number(uploaded) << "/" << QString::number(total);
});
return a.exec();
}