有时候我们想简单实现文件上传的功能,又不想使用额外的语言(比如PHP、Java),或者想实现文件的断点续传。这个时候Nginx的一个模块nginx-upload-module就能满足我们的需求。
下载模块:
cd /tmp wget https://codeload.github.com/vkholodkov/nginx-upload-module/zip/2.2 unzip 2.2
安装模块:
.configure --add-module=/tmp/nginx-upload-module-2.2/
nginx.conf配置:
server { [...] location /upload { upload_pass @uploadHandler; upload_store /usr/local/nginx/upload_temp 1; upload_set_form_field $upload_field_name.path "$upload_tmp_path"; } location @uploadHandler { proxy_pass http://backend-host; } [...] }
这里在server里定义了upload location,这个location是上传的接口,还有@uploadHandler location,是当文件上传完成后,nginx模块会对这个location发送一些必要的信息,如文件上传的路径。
这里涉及了几个指令:
server { [...] location /resumable_upload { upload_resumable on; upload_state_store /usr/local/nginx/upload_temp ; upload_pass @drivers_upload_handler; upload_store /usr/local/nginx/upload_temp; upload_set_form_field $upload_field_name.path "$upload_tmp_path"; } location @resumable_upload_handler { proxy_pass http://localhost:8002; } [...] }
与上一步multipart/form-data表单上传示例配置不同的地方有:
upload_resumable on: 开启断点续传功能; upload_state_store /usr/local/nginx/upload_temp: 设置断点续传状态文件存储的目录。POST /upload HTTP/1.1 Host: example.com Content-Length: 51201 Content-Type: application/octet-stream Content-Disposition: attachment; filename="big.TXT" X-Content-Range: bytes 0-51200/511920 Session-ID: 1111215056 <0-51200的字节文件数据>
HTTP/1.1 201 Created Date: Thu, 02 Sep 2010 12:54:40 GMT Content-Length: 14 Connection: close Range: 0-51200/511920 0-51200/511920
POST /upload HTTP/1.1 Host: example.com Content-Length: 51111 Content-Type: application/octet-stream Content-Disposition: attachment; filename="big.TXT" X-Content-Range: bytes 460809-511919/511920 Session-ID: 1111215056 <460809-511919字节文件数据>
HTTP/1.1 200 OK Date: Thu, 02 Sep 2010 12:54:43 GMT Content-Type: text/html Connection: close Content-Length: 2270 <响应的内容>
#!/usr/bin/python # -*- coding: utf-8 -*- import os.path import requests import hashlib # 待上传文件路径 FILE_UPLOAD = "/tmp/testfile" # 上传接口地址 UPLOAD_URL = "http://host/drivers_upload" # 单个片段上传的字节数 SEGMENT_SIZE = 1048576 def upload(fp, file_pos, size, file_size): session_id = get_session_id() fp.seek(file_pos) payload = fp.read(size) content_range = "bytes {file_pos}-{pos_end}/{file_size}".format(file_pos=file_pos, pos_end=file_pos+size-1,file_size=file_size) headers = {'Content-Disposition': 'attachment; filename="big.TXT"','Content-Type': 'application/octet-stream', 'X-Content-Range':content_range,'Session-ID': session_id,'Content-Length': size} res = requests.post(UPLOAD_URL, data=payload, headers=headers) print(res.text) # 根据文件名hash获得session id def get_session_id(): m = hashlib.md5() file_name = os.path.basename(FILE_UPLOAD) m.update(file_name) return m.hexdigest() def main(): file_pos = 0 file_size = os.path.getsize(FILE_UPLOAD) fp = open(FILE_UPLOAD,"r") while True: if file_pos + SEGMENT_SIZE >= file_size: upload(fp, file_pos, file_size - file_pos, file_size) fp.close() break else: upload(fp, file_pos, SEGMENT_SIZE, file_size) file_pos = file_pos + SEGMENT_SIZE if __name__ == "__main__": main()
http://www.nginx.com/resources/wiki/modules/upload/
http://www.grid.net.ru/nginx/upload.en.html