菜鸟笔记
提升您的技术认知

qt实现http文件上传下载(flask服务端)-ag真人游戏

1.准备服务端测试代码

只需要上传和下载两个接口,实际应用时可能还需要 token 验证之类的,而且也没有对文件传输结果进行校验。

#using flask 2.0.1
import os,sys
from flask import flask,request,jsonify,send_file,send_from_directory
app = flask(__name__)
filename_temp = ''
base_path=os.path.join(os.path.dirname(os.path.abspath(__file__)),'upload')
#测试
@app.route('/',methods=['get','post'])
def hello():
    return '

hello!

' #上传 @app.route('/upload',methods=['post']) def upload_file(): try: global filename_temp f = request.files['myfile'] filename_temp = f.filename print('upload file:' f.filename) f.save(os.path.join(base_path,f.filename)) return jsonify({ 'filename':f.filename, 'fileid':0 #假装对每个文件返回一个id,然后通过id再下载 }) except exception as e: print('error:' str(e)) return jsonify({'error':0}),0 #下载 @app.route('/download/',methods=['get']) def download_file(fileid): try: global filename_temp print('download file:' filename_temp) #假装是通过id从数据库拿到的文件 return send_from_directory(base_path,filename_temp,as_attachment=true) except exception as e: print('error:' str(e)) return jsonify({'error':0}),0 if __name__ == '__main__': print('server runing... ...') if not os.path.exists(base_path): os.makedirs(base_path) app.run(host='127.0.0.1',port=12345,debug=true)

传文件主要是借助 qhttpmultipart 类,并设置 content-type 为 multipart/form-data。我用 flask 测试的时候,要给 qhttppart 设置 multipart/form-data ,flask 的 request.files 才能拿到 form-data 的 filename 等信息。

form-data 里的 name 设置为某个值如 "myfile" 后,flask 里可以用 request.files['myfile'] 获取到这个 part,进而拿到设置的 filename。

注意 get/post 返回的 qnetworkreply 需要自己释放,qt 5.14 可以设置 qnetworkaccessmanager 的 setautodeletereplies(true) 自动释放,qt 5.15 又新增了 settransfertimeout 设置超时时间。

有些情况还需要设置 qhttpmultipart 的 boundary,不过我这个测试 demo 暂时用不到。

void httpmanager::upload(const qstring &url, const qstring &filepath)
{
    qdebug()<<"[upload file]"<open(qiodevice::readonly)){
        file->deletelater();
        qdebug()<<"open file error";
        return;
    }
    qnetworkrequest request;
    request.set);
    //request.setrawheader("content-type","multipart/form-data");
    //qhttpmultipart需要在请求完成后释放
    qhttpmultipart *multi_part = new qhttpmultipart(qhttpmultipart::formdatatype);
    qhttppart file_part;
    file_part.setheader(qnetworkrequest::contentdispositionheader,
                        qvariant(qstring("form-data; name=\"myfile\"; filename=\"%1\";")
                                 .arg(qfileinfo(filepath).filename())));
    //part.header加上这句flask.request.files才能拿到form-data的信息
    //注意不是request的header
    file_part.setrawheader("content-type", "multipart/form-data");
    file_part.setbodydevice(file);
    file->setparent(multi_part);
    multi_part->append(file_part);
    qnetworkreply *reply = manager.post(request,multi_part);
    multi_part->setparent(reply); //在删除reply时一并释放
    //因为是测试所以同步等待
    qeventloop eventloop;
    //上传进度
    connect(reply, &qnetworkreply::uploadprogress,
            this, [this](qint64 bytessent, qint64 bytestotal){
        qdebug()<<"[upload file] bytessend"<attribute(qnetworkrequest::httpstatuscodeattribute).toint();
    qdebug()<<"reply"<readall());
    qdebug()<<"[upload file] finished";
}

文件的下载相对就更简单的,只是要注意处理下载的异常情况。

void httpmanager::download(const qstring &url, const qstring &fileid, const qstring &filepath)
{
    qdebug()<<"[download file]"<isopen()){
               if(!reply->open(qiodevice::readonly)){
                   qdebug()<<"[download file] reply open failed";
                   return;
               }
           }
           if(!file.isopen()){
               if(!file.open(qiodevice::writeonly | qiodevice::append)){
                   qdebug()<<"[download file] file open failed";
                   return;
               }
           }
           file.write(reply->readall());
    });
    //下载进度
    connect(reply, &qnetworkreply::downloadprogress,
            this, [this](qint64 bytesreceived, qint64 bytestotal){
        qdebug()<<"[download file] bytesreceived"<attribute(qnetworkrequest::httpstatuscodeattribute).toint();
    //如果是无效的响应吧数据清除
    if(status_code != 200)
        file.remove();
    qdebug()<<"reply"<readall());
    qdebug()<<"[download file] finished";
}

我的 demo 只是测试了两个功能的基本使用,很多异常场景需要自己根据需求处理。对于大文件,目前测试将近 4g 可以正常上传下载,但是下载时可能会阻塞当前线程(我的 demo 没多线程所以界面会假死)。下面两个是个上传后下载的文件,分别为 1g 和 3点8g:

我的示例链接:https://github.com/gongjianbo/mytestcode/tree/master/qt/testqt_20210807_httpfile

网站地图