1.场景

1.在服务器运维过程中, 难免需要上传本地软件包文件到服务器上进行部署或者临时测试使用,在系统安全和服务器默认不允许进行直接上传文件到服务器上.针对这样的场景小工具上传文件场景横空出世.本章采用 Nginx+flask-html 简单实现文件上传下载等功能.(本方案不支持断点查询和超过1G大文件上传.单次只能上传一个文件,支持配置支持后缀名文件 gz,zip,jar,sh,py 多次上传同一个文件会进行强制覆盖老同文件名文件)

2.配置nginx反向代理应用程序和上传域名和下载域名

#1.文件上传域名配置
upstream flask-upload {
        server 127.0.0.1:8888 max_fails=3 fail_timeout=10s;
}
server{
    listen     80;
    server_name  ;
    client_max_body_size 1024m; # 限制客户端最大的Body-Size 1G
    access_log /data/new/app/upload/logs/op-upload-breaklinux.log;
    auth_basic   "rd";  #nginx登录权限模块
    auth_basic_user_file /data/new/app/upload/pass_file;#权限文件
    location / {
	proxy_next_upstream http_500 http_404 http_502;
	proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	proxy_pass http://flask-upload;
	proxy_store off;
	proxy_buffering off;
	proxy_cache_use_stale off;
	proxy_connect_timeout 10s;
	proxy_send_timeout 1000s;
	proxy_read_timeout 1000s;
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Headers X-Requested-With;
        add_header Access-Control-Allow-Methods GET,POST,OPTIONS,HEAD;
}
}

#2.文件下载域名配置

server{
        listen     80;
        server_name ;
	client_max_body_size 1024m; # 限制客户端最大的Body-Size
        access_log  /data/new/app/logs/op-download.breaklinux.log;
        location / {
                  root /data/new/app/flask-api-upload/;
                  autoindex on;             #开启索引功能
                  autoindex_exact_size off; # 关闭计算文件确切大小(单位bytes),只显示大概大小(单位kb、mb、gb)
                  autoindex_localtime on;
              }
}

3.后端服务API服务和前端 html 代码*

#-*- coding: utf-8 -*-
import os
import json
from flask import Flask, request, Response, url_for, send_from_directory
from werkzeug.utils import secure_filename

"""
1.设置文件上传支持格式,
2.指定文件上传系统路径;
3.配置flask 上传文件配置;
4.指定html静态页面代码;
"""
ALLOWED_EXTENSIONS = set(['gz', 'zip', 'jar', 'sh', 'py'])
UPLOAD_FOLDER = "flask-api-upload/"
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
html = '''
 <!doctype html>
<html lang="en">
  <head>
     <link rel="stylesheet" href="https:///npm/bootstrap@4.5.0/dist/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  </head>
  <body>
    <script src="https:///npm/jquery@3.5.1/dist/jquery.slim.min.js" integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj" crossorigin="anonymous"></script>
   <script src="https:///npm/popper.js@1.16.0/dist/usm/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https:///npm/bootstrap@4.5.0/dist/js/bootstrap.min.js" integrity="sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI" crossorigin="anonymous"></script>
<form enctype="multipart/form-data" method="post">
    <div style="margin-top:50px" class="container">
        欢迎来到运维文件上传系统
    <hr style="filter: progid:dximagetransform.microsoft.glow(color="#3366FF",strength=3" width="100%" color="#3366FF" size=5>
  <div class="form-group col-sm-4">
      <label for="inputAddress">上传文件</label>
        <label for="exampleFormControlFile1"></label>
        <input type="file" name="file" class="form-control-file" id="exampleFormControlFile1">
 </div>
  <button type="submit" name="submit" class="btn btn-primary">Sign in</button>
</form>
  </div>
  </body>
</html>
'''

def allowed_file(filename):
    """
    1.文件后缀名匹配校验支持文件格式
    :param filename:
    :return:
    """
    return '.' in filename and \
           filename.rsplit('.', 1)[1] in ALLOWED_EXTENSIONS

def check_upload_dir():
    """
    1.检查上传目录是否存在,不存在创建目录.存在返回false
    :return:
    """
    import os
    isExists = os.path.exists(UPLOAD_FOLDER)
    if not isExists:
        os.makedirs(UPLOAD_FOLDER)
        return True
    else:
        return False

@app.route('/', methods=['GET', 'POST'])
def upload_file():
    """
    1.获取前端表单参数,进行文件上传带指定路径中
    2.判断前端参数是否存在空参数,
    3.返回文件获取域名加文件访问路径,
    :return:
    """
    if request.method == 'POST':
        file = request.files['file']
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            get_url = "http://your_access_url/" + file.filename
            return Response(json.dumps({"code": 0, "data": "upload sucess", "get_url": get_url}),
                            mimetype='application/json')
        else:
            return Response(
                json.dumps({"code": 1, "msg": "file Type no unsupported ", "file_List": "zip,tar,jar,sh,py"}),
                mimetype='application/json')
    return html

if __name__ == '__main__':
    check_upload_dir()
    app.run(
        host="172.26.0.149",
        port=8888,
        debug=True
    )

4.客户端访问测试 image.png