FastDFS结合Flask使用
0、写在前面
原本的文件上传下载都是自己结合网上的代码实现的,用起来扩展性不强,性能也不行。
后来发现才知道有这种造好的轮子。扩展性强,性能也强。
1、技术原理
原理大概就是这张图了。其中tracker和storage需要使用docker安装,client有基于各种语言的实现,大概就是个接口文件。
2、安装fastdfs
安装完成的storage docker自带nginx,默认开启8888端口
#docker搜索文件 docker search fastdfs #拉取官方 docker pull delron/fastdfs #查看镜像 docker images #使用docker镜像构建tracker容器(跟踪服务器,起到调度的作用)
docker run -d --network=host --name tracker -v /var/fdfs/tracker:/var/fdfs delron/fastdfs tracker
#使用docker镜像构建storage容器(存储服务器,提供容量和备份服务)
docker run -d --network=host --name storage -e TRACKER_SERVER=ip:22122 -v /var/fdfs/storage:/var/fdfs -e GROUP_NAME=group1 delron/fastdfs storage
3、安装fdfs-client-py
1.先安装依赖包mutagen、requests
2.直接安装会报错,官方下载压缩包 https://github.com/JaceHo/fdfs_client-py
3.打开 storage_client.py 注释 12行 如图所示:
4.把fdfs_client文件夹直接复制到python环境的lib文件夹里
4、在python中连接使用fastdfs
conf文件需要改动两处,base_path=日志存放路径,tracker_server=服务器IP:22122
# connect timeout in seconds # default value is 30s # Note: in the intranet network (LAN), 2 seconds is enough. connect_timeout = 5 # network timeout in seconds # default value is 30s network_timeout = 60 # the base path to store log files base_path = C://Users//Administrator//Desktop//py//test//test1 # tracker_server can ocur more than once for multi tracker servers. # the value format of tracker_server is "HOST:PORT", # the HOST can be hostname or ip address, # and the HOST can be dual IPs or hostnames seperated by comma, # the dual IPS must be an inner (intranet) IP and an outer (extranet) IP, # or two different types of inner (intranet) IPs. # for example: 192.168.2.100,122.244.141.46:22122 # another eg.: 192.168.1.10,172.17.4.21:22122 tracker_server = 61.6.192.148:22122 #tracker_server = 192.168.0.197:22122 #standard log level as syslog, case insensitive, value list: ### emerg for emergency ### alert ### crit for critical ### error ### warn for warning ### notice ### info ### debug log_level = info # if use connection pool # default value is false # since V4.05 use_connection_pool = false # connections whose the idle time exceeds this time will be closed # unit: second # default value is 3600 # since V4.05 connection_pool_max_idle_time = 3600 # if load FastDFS parameters from tracker server # since V4.05 # default value is false load_fdfs_parameters_from_tracker = false # if use storage ID instead of IP address # same as tracker.conf # valid only when load_fdfs_parameters_from_tracker is false # default value is false # since V4.05 use_storage_id = false # specify storage ids filename, can use relative or absolute path # same as tracker.conf # valid only when load_fdfs_parameters_from_tracker is false # since V4.05 storage_ids_filename = storage_ids.conf #HTTP settings http.tracker_server_port = 80 #use "#include" directive to include HTTP other settiongs ##include http.conf
from fdfs_client.client import Fdfs_client client = Fdfs_client('C:\\Users\\Administrator\\Desktop\\py\\test\\test1\\client.conf') ret = client.upload_by_filename('C:\\Users\\Administrator\\Desktop\\py\\test\\test1\\zzzz.jpg') print(ret)
5、在Flask中使用fastdfs
# -*- coding: UTF-8 -*- from flask import Flask,render_template,request,send_file from fdfs_client.client import Fdfs_client import io app = Flask(__name__) def getFileExt(filename): return ('%s' % filename.split('.')[-1]).lower() @app.route('/') def index(): return render_template('index.html') #上传,通用下载,适用于图片等公开的文件 @app.route('/upload',methods=['GET','POST']) def upload(): print(request.files['_file']) saved_file_name = request.files['_file'].filename client = Fdfs_client('C:\\Users\\Administrator\\Desktop\\py\\test\\test1\\client.conf') #二进制存储 ret = client.upload_by_buffer(request.files['_file'].read(),getFileExt(saved_file_name)) saved_file = 'http://61.6.192.148:8888/'+ ret['Remote file_id'] return render_template('index.html',ret=ret,saved_file=saved_file,saved_file_name=saved_file_name) #下载,可在fastfds的storage中的配置文件配置只允许后端访问,适用于非公开的文件 @app.route('/download/',methods=['GET','POST']) def download(): file_id = request.args['file_id'].replace('\\\\','/') print(file_id) client = Fdfs_client('C:\\Users\\Administrator\\Desktop\\py\\test\\test1\\client.conf') #二进制读取 saved_file_buffer = client.download_to_buffer(file_id) return send_file(io.BytesIO(saved_file_buffer['Content']), attachment_filename=file_id,) if __name__ == '__main__': app.run(debug=True)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> 文件上传:<br> <form enctype="multipart/form-data" method="post" action="/upload"> <input type="file" name="_file"/> <input type="submit" name="submit"> </form> <br> <a href="{{ saved_file }}">{{saved_file_name }}</a> <br> {{ ret }} </body> </html>