电脑疯子技术论坛|电脑极客社区

微信扫一扫 分享朋友圈

已有 1825 人浏览分享

nginx-upload-module模块实现文件断点续传

[复制链接]
1825 0

每当我们想简单的实现文件上传功能,而又不使用其他的语言(比如PHP、Java),或者想实现文件的断点续传。

这个时候Nginx的一个模块nginx-upload-module就能满足我们的需求。

模块安装


下载模块:

  1. cd /tmp
  2. wget https://codeload.github.com/vkholodkov/nginx-upload-module/zip/2.2
  3. unzip 2.2
复制代码


安装模块:

  1. .configure --add-module=/tmp/nginx-upload-module-2.2/
复制代码


multipart/form-data表单上传示例

nginx.conf配置:
  1. server {
  2.   [...]
  3.          location /upload {
  4.                 upload_pass @uploadHandler;
  5.                 upload_store /usr/local/nginx/upload_temp 1;
  6.                 upload_set_form_field $upload_field_name.path "$upload_tmp_path";
  7.         }
  8.      
  9.          location @uploadHandler {
  10.                 proxy_pass http://backend-host;
  11.         }
  12.     [...]
  13.     }
复制代码


这里在server里定义了upload location,这个location是上传的接口,还有@uploadHandler location,

是当文件上传完成后,nginx模块会对这个location发送一些必要的信息,如文件上传的路径,这里涉及了几个指令:

  1. upload_pass @uploadHandler:上传完成后会发送必要的数据到@uploadHandler;
  2. upload_store /usr/local/nginx/upload_temp 1: 文件上传的临时目录;
  3. upload_set_form_field $upload_field_name.path “$upload_tmp_path”: 设置文件上传完成后,把文件临时路径发送给upload_pass指定的location。
复制代码


断点续传示例


nginx.conf配置

  1. server {
  2. [...]
  3.         location /resumable_upload {
  4.                upload_resumable on;
  5.                upload_state_store /usr/local/nginx/upload_temp ;
  6.                upload_pass @drivers_upload_handler;
  7.                upload_store /usr/local/nginx/upload_temp;
  8.                upload_set_form_field $upload_field_name.path "$upload_tmp_path";
  9.             }
  10.      
  11.          location @resumable_upload_handler {
  12.                proxy_pass http://localhost:8002;
  13.         }
  14.     [...]
  15.     }
复制代码

  1. 与上一步multipart/form-data表单上传示例配置不同的地方有:
  2. upload_resumable on: 开启断点续传功能;
  3. upload_state_store /usr/local/nginx/upload_temp: 设置断点续传状态文件存储的目录。
复制代码


上传文件第一个片段
  1. POST /upload HTTP/1.1
  2. Host: example.com
  3. Content-Length: 51201
  4. Content-Type: application/octet-stream
  5. Content-Disposition: attachment; filename="big.TXT"
  6. X-Content-Range: bytes 0-51200/511920
  7. Session-ID: 1111215056
  8.    
  9. <0-51200的字节文件数据>
复制代码


上传文件第一个片段服务器响应

  1. HTTP/1.1 201 Created
  2. Date: Thu, 02 Sep 2010 12:54:40 GMT
  3. Content-Length: 14
  4. Connection: close
  5. Range: 0-51200/511920
  6.      
  7. 0-51200/511920
复制代码


上传文件最后一个片段

  1. POST /upload HTTP/1.1
  2. Host: example.com
  3. Content-Length: 51111
  4. Content-Type: application/octet-stream
  5. Content-Disposition: attachment; filename="big.TXT"
  6. X-Content-Range: bytes 460809-511919/511920
  7. Session-ID: 1111215056

  8. <460809-511919字节文件数据>
复制代码


上传文件最后一个片段服务器响应

  1. HTTP/1.1 200 OK
  2. Date: Thu, 02 Sep 2010 12:54:43 GMT
  3. Content-Type: text/html
  4. Connection: close
  5. Content-Length: 2270
  6.      
  7. < 响应的内容>
复制代码


请求头说明

  1. 请求头                               说明
  2. Content-Disposition  attachment, filename=“上传的文件名”
  3. Content-Type              待上传文件的mime type,如application/octet-stream(注:不能为multipart/form-data)
  4. X-Content-Range      待上传文件字节范围,如第一片段bytes 0-51200/511920,最后一个片段bytes 460809-511919/511920(注:文件第一个字节标号为0,最后一个字节标号为n-1,其中n为文件字节大小)
  5. X-Session-ID              上传文件的标识,由客户端随机指定.因为是断点续传,客户端必须确保同一个文件的所有片段上传标识一致
  6. Content-Length              上传片段的大小
复制代码


Python上传demo

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3.      
  4. import os.path
  5. import requests
  6. import hashlib
  7.      
  8. # 待上传文件路径
  9. FILE_UPLOAD = "/tmp/testfile"
  10. # 上传接口地址
  11. UPLOAD_URL = "http://host/drivers_upload"
  12. # 单个片段上传的字节数
  13. SEGMENT_SIZE = 1048576
  14.    
  15. def upload(fp, file_pos, size, file_size):
  16.         session_id = get_session_id()
  17.         fp.seek(file_pos)
  18.         payload = fp.read(size)
  19.         content_range = "bytes {file_pos}-{pos_end}/{file_size}".format(file_pos=file_pos,
  20.                         pos_end=file_pos+size-1,file_size=file_size)
  21.         headers = {'Content-Disposition': 'attachment; filename="big.TXT"','Content-Type': 'application/octet-stream',
  22.                     'X-Content-Range':content_range,'Session-ID': session_id,'Content-Length': size}
  23.         res = requests.post(UPLOAD_URL, data=payload, headers=headers)
  24.         print(res.text)
  25.      
  26.      
  27. # 根据文件名hash获得session id
  28. def get_session_id():
  29.   m = hashlib.md5()
  30.   file_name = os.path.basename(FILE_UPLOAD)
  31.   m.update(file_name)
  32.   return m.hexdigest()
  33.      
  34. def main():
  35.   file_pos = 0
  36.   file_size = os.path.getsize(FILE_UPLOAD)
  37.   fp = open(FILE_UPLOAD,"r")
  38.      
  39.   while True:
  40.    if file_pos + SEGMENT_SIZE >= file_size:
  41.        upload(fp, file_pos, file_size - file_pos, file_size)
  42.        fp.close()
  43.        break
  44.    else:
  45.      upload(fp, file_pos, SEGMENT_SIZE, file_size)
  46.      file_pos = file_pos + SEGMENT_SIZE
  47.      
  48. if __name__ == "__main__":
  49.         main()
复制代码





您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

关注

0

粉丝

9021

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Powered by Pcgho! X3.4

© 2008-2022 Pcgho Inc.