基于nginx搭建简单的文件服务器
基于nginx搭建简单的文件服务器
前言
对于文件的上传和下载是目前的后端中及其常见的一种功能,我们可以使用私有云存储,例如阿里云、七牛云等,我们也可以直接写接口,保存上传的文件,返回已上传的文件。但是私有云存储需要一定的费用,自己写接口共用性又不高,而且需要写一堆雷同的业务逻辑,于是乎,最近我在寻找比较省力(主要是我懒)又省钱的方法来解决这个问题,然后我发现nginx可以使用模块来实现这个功能,以下就是我对这次实践的分享。
环境
- centos 7.6
开始搭建
下载nginx
[root@localhost ~]# wget http://nginx.org/download/nginx-1.16.1.tar.gz
[root@localhost ~]# ls
anaconda-ks.cfg nginx-1.16.1.tar.gz
[root@localhost ~]# tar zxf nginx-1.16.1.tar.gz
[root@localhost ~]# ls
anaconda-ks.cfg nginx-1.16.1 nginx-1.16.1.tar.gz
[root@localhost ~]#
下载nginx_upload_module
Nginx的服务由各个模块组成,nginx_upload_module模块用于接受并处理用户上传的文件,该模块最初的版本是十几年前的了,但是目前仍然才2.2.0版本。
-
官方地址
官方版本存在比较大的bug,网上也有很多解决方案,比如这里,喜欢折腾的可以去尝试下;如果不想折腾请直接去已修复版本克隆下载下来使用。
[root@localhost ~]# git clone https://github.com/martaintao/nginx-upload-module.git Cloning into 'nginx-upload-module'... remote: Enumerating objects: 32, done. remote: Total 32 (delta 0), reused 0 (delta 0), pack-reused 32 Unpacking objects: 100% (32/32), done. [root@localhost ~]# ls anaconda-ks.cfg nginx-1.16.1 nginx-1.16.1.tar.gz nginx-upload-module [root@localhost ~]#
编译安装
-
安装依赖库
[root@localhost nginx-1.16.1]# yum install openssl-devel pcre-devel -y
-
开始编译
[root@localhost nginx-1.16.1]# ./configure --prefix=/usr/local/nginx --add-module=../nginx-upload-module --with-http_ssl_module ... configuring additional modules adding module in ../nginx-upload-module + ngx_http_upload_module was configured checking for PCRE library ... found checking for PCRE JIT support ... found checking for OpenSSL library ... found checking for zlib library ... found creating objs/Makefile Configuration summary + using system PCRE library + using system OpenSSL library + using system zlib library nginx path prefix: "/usr/local/nginx" nginx binary file: "/usr/local/nginx/sbin/nginx" nginx modules path: "/usr/local/nginx/modules" nginx configuration prefix: "/usr/local/nginx/conf" nginx configuration file: "/usr/local/nginx/conf/nginx.conf" nginx pid file: "/usr/local/nginx/logs/nginx.pid" nginx error log file: "/usr/local/nginx/logs/error.log" nginx http access log file: "/usr/local/nginx/logs/access.log" nginx http client request body temporary files: "client_body_temp" nginx http proxy temporary files: "proxy_temp" nginx http fastcgi temporary files: "fastcgi_temp" nginx http uwsgi temporary files: "uwsgi_temp" nginx http scgi temporary files: "scgi_temp" [root@localhost nginx-1.16.1]# make & make install
-
如果中途没有什么报错就说明编译安装成功了!
编写配置文件
前期准备
因为需要实现上传
和下载
功能,所以我们需要提前准备好相应的目录。这里我准备了两个目录:/var/www/tmp
和/var/www/resource
,tmp
目录为文件上传的临时目录,resource
目录为实际存储和下载的目录。这里注意,我们需要保证两个目录的权限。
[root@localhost www]# pwd
/var/www
[root@localhost www]# ll
total 0
drwxrwxrwx. 2 root root 6 May 18 08:10 resource
drwxrwxrwx. 2 root root 6 May 18 08:10 tmp
[root@localhost www]#
配置nginx
这里主要是关于上传的配置,因为下载非常简单。
server {
listen 80;
server_name localhost;
#文件下载配置
location /download {
# 这里设置下载的文件目录
alias /var/www/resource;
#是否打开目录结构(视情况是否打开),即直接访问xxx.com/download是否需要显示出文件目录结构
autoindex on;
}
#文件上传相关配置
location /upload {
# 配置文件上传大小
client_max_body_size 50m;
# 转到后台处理URL
upload_pass @uploadhandle;
# 临时保存路径 (暂时保存此处,使用回调处理,将临时文件变成真实有效文件)
# 可以使用散列
upload_store /var/www/tmp;
upload_pass_args on;
# 上传文件的权限,rw表示读写 r只读
upload_store_access user:rw;
# 这里写入http报头,pass到后台页面后能获取这里set的报头字段
upload_set_form_field "${upload_field_name}_name" $upload_file_name;
upload_set_form_field "${upload_field_name}_content_type" $upload_content_type;
upload_set_form_field "${upload_field_name}_path" $upload_tmp_path;
# Upload模块自动生成的一些信息,如文件大小与文件md5值,可供上传后台处理
upload_aggregate_form_field "${upload_field_name}_md5" $upload_file_md5;
upload_aggregate_form_field "${upload_field_name}_size" $upload_file_size;
# 允许的字段,允许全部可以 "^.*$"
#upload_pass_form_field "^submit$|^description$";
upload_pass_form_field "^.*$";
# 每秒字节速度控制,0表示不受控制,默认0
upload_limit_rate 0;
# 如果pass页面是以下状态码,就删除此次上传的临时文件
upload_cleanup 400 404 499 500-505;
}
# upload_pass 不支持uri添加/(可以使用alias)
location @uploadhandle {
#下面这个配置等同于访问:http://localhost:9999/upload,这里暂时不做演示
# proxy_pass http://localhost:9999;
return 200; # 如果不需要后台处理,可以直接返回200
}
}
上传原理
nginx文件上传- 上传文件到
/upload
-
nginx
服务器接收到文件,先把文件保存到/var/www/tmp
目录下,文件名为随机,但文件相关信息会转发给回调程序
-
回调程序
经过验证之后,返回文件信息。对于文件的处理根据具体需求来保存
或删除
。
参数解释
假如按照上面的配置的话,如果我们使用formData传一个键值为test
的文件upload.conf
到服务器。
其中,服务器获取到之后,配置中的upload_field_name
就是键值名test
.回调程序获取到的转发的form里面是这样的:
'test_name':'upload.conf',
'test_content_type':'text/plain',
'test_path',:'/var/www/tmp/0000000012',
'test_md5':'115abcb34ef9c1ff1191bb63b1ef15a9',
'test_size', '1396'
回调程序
网上许多人使用Lua开发回调程序,我们也可以使用任何一种后端语言来实现回调程序,由于时间原因,后面在分享我一个回调程序的实例...o(╥﹏╥)o
- 使用python接收回调
# encoding=utf8
from flask import Flask, request, jsonify
from gevent import pywsgi
from flask_cors import CORS
import shutil
import os
import time
app = Flask(__name__)
app.debug = True
app.config['JSON_AS_ASCII'] = False
CORS(app, supports_credentials=True)
download_path_prefix = "/var/www/download"
@app.route("/upload", methods=["GET", "POST", "OPTIONS", "PUT", "DELETE"])
def hello():
file_name = request.form["file_name"]
file_content_type = request.form["file_content_type"]
file_path = request.form["file_path"]
file_md5 = request.form["file_md5"]
file_size = request.form["file_size"]
save_file_name = str(int(time.time()))+"-"+file_name
shutil.move(file_path, os.path.join(download_path_prefix,save_file_name))
res = {
"uploadFileName":file_name,
"fileContentType":file_content_type,
"fileSize":file_size,
"fileUrl":"http://x.x.x.x/download/"+save_file_name
}
return success_with_data(res)
def success():
return response(0, "success")
def success_with_data(data):
return response(0, "success", data)
def fail(msg):
return response(-1, msg)
def response(status, msg, data=''):
return jsonify({'status': status, 'msg': msg, 'data': data})
if __name__ == "__main__":
server = pywsgi.WSGIServer(('0.0.0.0', 9999), app)
server.serve_forever()