背景
开学一个多月了,由于繁重的学业和懒惰,都没怎么更新有意思的博客。
前几天突然想到了一个想法。同学之间平常用网络分享一个文件,大部分都是用的qq。但是qq看起来把文件拖到聊天框点击发送就发给对面同学了。但是实际上是先上传到了腾讯的服务器,然后对面的同学再从服务器上下载。
这一上传一下载就很耽误时间。我就想在我的电脑上开一个文件上传服务,别的同学直接上传到我的机械革命上,上传完毕,我就得到了这个文件,不用再下载一遍。而且由于是校园网内的服务,速度也有保障。
语言选择
由于前几天做了几道python flask模板注入的题目,便打算拿flask来当后端练练手,提供http服务。
前端的话还是利用漂亮且方便易用的fomantic-ui解决html和css样式问题,再配合上大大简化js编程的Jquery
来写效果和功能。
遇到的困难
单纯的文件上传十分简单。对付小文件还好,但是大文件就会出现页面停滞的情况,而用户收不到任何反馈,不知道到底是在上传还是崩溃了。我们需要设置一个上传进度条来给以用户友善的提示。所以这里就有一个问题,如何获得上传的进度?
查询资料过后,我发现XMLHttpRequest能够获取进度。然后我又发现Jquery
中封装的$.ajax
能够更加简单的实现。参考链接 https://stackoverflow.com/questions/13203231/is-there-any-way-to-get-jquery-ajax-upload-progress
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| <!DOCTYPE html> <html> <head> <meta charset="utf8" /> <script src="https://cdn.jsdelivr.net/npm/jquery@3.3.1/dist/jquery.min.js"></script> <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/fomantic-ui@2.8.8/dist/semantic.min.css" /> <script src="https://cdn.jsdelivr.net/npm/fomantic-ui@2.8.8/dist/semantic.min.js"></script> <title>wuuconix's page</title> </head> <body> <div style="padding-top: 5em;"></div> <div class="ui text container"> <div class="ui placeholder segment"> {% if filelist == [] %} <div class="ui icon header"> <i class="pdf file outline icon"></i> 目前文件夹里空空如也 </div> {% else %} <div class="ui list"> {% for file in filelist%} <div class="item"> <i class="file icon"></i> <div class="content"> <a class="header" href="download/{{file}}" data-content="点击下载{{file}}" id="files">{{file}}</a> </div> </div> {% endfor %} </div> {% endif %} <div class="ui buttons"> <button class="ui primary button" id="button_choose">选择文件</button> <button class="ui positive button" id="button_submit">上传</button> </div> <form action="/upload" method="post" enctype="multipart/form-data" id="form"> <input type="file" id="input_file" style="display: none;" name="file"> </form> <div class="ui divider"></div> <div class="ui indicating progress" id="progress" data-value="0" data-total="100"> <div class="bar"> <div class="progress"></div> </div> <div class="label"></div> </div> </div> </div> </body>
<script> $(document).ready(function(){ $("#progress").hide(); $("#button_submit").attr("disabled", true); }); $("#button_choose").click(function() { $("#input_file").click(); }); $("#input_file").bind("input propertychange",function(){ var name = ($(this).prop('files')[0]['name']); $("#button_submit").attr("disabled", false); $('#button_choose')[0].innerHTML=name; }); $("#button_submit").click(function() { $("#progress").show(); var formdata = new FormData($("#form")[0]); $.ajax({ url:'/upload', type:'post', xhr: function () { var xhr = $.ajaxSettings.xhr(); var starttime = Math.ceil(new Date().getTime() / 1000); xhr.upload.onprogress = function (e) { if (e.lengthComputable) { var uploaded = Math.ceil(e.loaded / Math.pow(1024,2)); var spenttime = Math.ceil(new Date().getTime() / 1000) - starttime; var speed = (uploaded / spenttime).toFixed(2); var progress = Math.ceil(e.loaded / e.total * 100); $("#progress").attr('data-value', progress); $("#progress").progress('update progress', progress); $("#progress").progress('set label', speed + "MB/s"); } }; return xhr; }, processData:false, contentType:false, data:formdata, success:function (data) { $('body').toast({ title: '恭喜你', message: "你已经成功将 《" + $('#button_choose')[0].innerHTML + "》 上传至了武丑兄的机械革命。页面即将自动刷新", showProgress: 'bottom', classProgress: 'red' }); setTimeout("location.reload();", 3000) } }) }); $('#progress').progress({ label: 'percent', }); $('a').popup({ on: 'hover' }); $("#button_submit").popup({ on: 'hover' }); </script>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| from flask import render_template, Flask, request, make_response, send_from_directory import os
def get_filelist(): filelist = os.listdir("upload/") return filelist
app = Flask(__name__)
@app.route('/') def hello(filelist=[]): return render_template("index.html", filelist=get_filelist())
@app.route('/upload',methods=['GET','POST']) def upload(): if request.method == 'POST': f = request.files['file'] print(request.files) f.save(f"upload/{f.filename}") filelist = get_filelist() return render_template("index.html", filelist=filelist) else: return render_template("index.html", filelist=get_filelist())
@app.route('/download/<filename>',methods=['GET']) def download(filename): response = make_response(send_from_directory("upload", filename, as_attachment=True)) response.headers["Content-Disposition"] = "attachment; filename={}".format(filename.encode().decode('latin-1')) return response if __name__ == '__main__': app.run(host='0.0.0.0', port=80)
|
效果