翼度科技»论坛 编程开发 python 查看内容

通过Python中的http.server搭建文件上传下载服务功能

8

主题

8

帖子

24

积分

新手上路

Rank: 1

积分
24


Python搭建文件下载服务

在Web开发中,文件下载服务是一个常见且基础的功能。Python的
  1. http.server
复制代码
模块提供了一个简单而强大的方式来搭建HTTP服务器,进而实现文件下载服务。本文将结合实际案例,详细介绍如何使用Python的
  1. http.server
复制代码
模块来搭建文件下载服务。

一、概述

Python的
  1. http.server
复制代码
模块是Python标准库的一部分,它提供了一个基本的HTTP服务器类和请求处理器。通过这个模块,我们可以轻松地搭建一个HTTP服务器,用于处理客户端的HTTP请求,包括文件下载请求。

1.1 准备工作

在开始之前,请确保你的计算机上已安装Python环境。Python 3.x版本已经内置了
  1. http.server
复制代码
模块,因此你不需要额外安装任何库。

1.2 场景描述

假设我们有一个需求:需要搭建一个HTTP服务器,用于提供特定目录下的文件下载服务。客户端通过访问服务器上的特定URL,即可下载服务器上的文件。

二、搭建HTTP服务器


2.1 基础服务器搭建

首先,我们将使用
  1. http.server
复制代码
模块搭建一个基础的HTTP服务器。

2.1.1 示例代码
  1. import http.server
  2. import socketserver
  3. # 设置端口号
  4. PORT = 8000
  5. # 创建一个TCP服务器
  6. with socketserver.TCPServer(("", PORT), http.server.SimpleHTTPRequestHandler) as httpd:
  7.     print("Serving at port", PORT)
  8.     # 启动服务器,使其一直运行
  9.     httpd.serve_forever()
复制代码

在上述代码中,我们导入了
  1. http.server
复制代码
  1. socketserver
复制代码
模块,并设置了服务器监听的端口号为8000。然后,我们创建了一个
  1. TCPServer
复制代码
实例,并将
  1. http.server.SimpleHTTPRequestHandler
复制代码
作为请求处理器传入。最后,我们调用
  1. serve_forever()
复制代码
方法启动服务器,使其持续运行。

2.1.2 运行服务器

将上述代码保存为一个
  1. .py
复制代码
文件,例如
  1. server.py
复制代码
。然后,在命令行中导航到该文件所在的目录,并执行以下命令:
  1. python server.py
复制代码
执行后,你将在控制台看到“Serving at port 8000”的提示,表示服务器已成功启动。


2.2 自定义文件目录

默认情况下,
  1. SimpleHTTPRequestHandler
复制代码
会处理服务器当前工作目录下的文件。然而,我们可能希望服务器处理特定目录下的文件。为了实现这一需求,我们可以创建一个继承自
  1. SimpleHTTPRequestHandler
复制代码
的类,并重写
  1. translate_path
复制代码
方法。

2.2.1 示例代码
  1. import http.server
  2. import socketserver
  3. import os
  4. # 定义服务器端口
  5. PORT = 8080
  6. # 定义文件目录
  7. DIRECTORY = "/path/to/your/directory"
  8. # 创建一个处理请求的类
  9. class MyHandler(http.server.SimpleHTTPRequestHandler):
  10.     def translate_path(self, path):
  11.         # 确保返回的路径在指定的目录内
  12.         path = os.path.normpath(os.path.join(DIRECTORY, path.lstrip('/')))
  13.         return path
  14. # 创建服务器
  15. with socketserver.TCPServer(("", PORT), MyHandler) as httpd:
  16.     print(f"Serving at port {PORT}")
  17.     # 启动服务器,使其一直运行
  18.     httpd.serve_forever()
复制代码
在上述代码中,我们定义了
  1. DIRECTORY
复制代码
变量来指定文件所在的目录,并创建了一个
  1. MyHandler
复制代码
类,该类继承自
  1. SimpleHTTPRequestHandler
复制代码
并重写了
  1. translate_path
复制代码
方法。在
  1. translate_path
复制代码
方法中,我们通过
  1. os.path.join
复制代码
  1. os.path.normpath
复制代码
函数将请求的路径与
  1. DIRECTORY
复制代码
变量拼接起来,并确保返回的路径在指定的目录内。

2.2.2 运行服务器

将上述代码保存为一个
  1. .py
复制代码
文件,并替换
  1. DIRECTORY
复制代码
变量的值为你希望服务器处理的文件目录。然后,按照2.1.2节中的步骤运行服务器。

2.3 上传下载服务

有时,我们可能需要定制HTTP响应头,以满足特定的需求。

2.3.1 示例代码

为了定制响应头,我们继续上面的例子,通过重写
  1. do_GET
复制代码
方法来设置特定的HTTP响应头,比如
  1. Content-Disposition
复制代码
以支持文件下载。
  1. import os
  2. import cgi
  3. from http.server import HTTPServer, BaseHTTPRequestHandler
  4. from urllib.parse import unquote
  5. class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
  6.     def do_GET(self):
  7.         # Parse the URL to get the file path
  8.         file_path = unquote(self.path.strip("/"))
  9.         if os.path.isfile(file_path):
  10.             # If the requested path is a file, serve the file as an attachment
  11.             self.send_response(200)
  12.             self.send_header('Content-Type', 'application/octet-stream')
  13.             # self.send_header('Content-Disposition', f'attachment; filename="{os.path.basename(file_path)}"')
  14.             self.end_headers()
  15.             with open(file_path, 'rb') as file:
  16.                 self.wfile.write(file.read())
  17.         else:
  18.             # Otherwise, show the upload form and file list
  19.             self.send_response(200)
  20.             self.send_header('Content-type', 'text/html')
  21.             self.end_headers()
  22.             # List files in the current directory
  23.             file_list = os.listdir('.')
  24.             file_list_html = ''.join(f'<li><a href="/{file}" rel="external nofollow" >{file}</a></li>' for file in file_list)
  25.             self.wfile.write(f'''
  26.                 <html>
  27.                 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  28.                 <body>
  29.                     <form enctype="multipart/form-data" method="post">
  30.                         <input type="file" name="file">
  31.                         <input type="submit" value="Upload">
  32.                     </form>
  33.                     <h2>Files in current directory:</h2>
  34.                     <ul>
  35.                         {file_list_html}
  36.                     </ul>
  37.                 </body>
  38.                 </html>
  39.             '''.encode())
  40.     def do_POST(self):
  41.         try:
  42.             content_type = self.headers['Content-Type']
  43.             if 'multipart/form-data' in content_type:
  44.                 form = cgi.FieldStorage(
  45.                     fp=self.rfile,
  46.                     headers=self.headers,
  47.                     environ={'REQUEST_METHOD': 'POST'}
  48.                 )
  49.                 file_field = form['file']
  50.                 if file_field.filename:
  51.                     # Save the file
  52.                     with open(os.path.join('.', file_field.filename), 'wb') as f:
  53.                         f.write(file_field.file.read())
  54.                     self.send_response(200)
  55.                     self.send_header('Content-type', 'text/html')
  56.                     self.end_headers()
  57.                     self.wfile.write(b'''
  58.                         <html>
  59.                         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  60.                         <body>
  61.                             <p>File uploaded successfully.</p>
  62.                             <script>
  63.                                 setTimeout(function() {
  64.                                     window.location.href = "/";
  65.                                 }, 2000);
  66.                             </script>
  67.                         </body>
  68.                         </html>
  69.                     ''')
  70.                 else:
  71.                     self.send_response(400)
  72.                     self.send_header('Content-type', 'text/html')
  73.                     self.end_headers()
  74.                     self.wfile.write(b'''
  75.                         <html>
  76.                         <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  77.                         <body>
  78.                             <p>No file uploaded.</p>
  79.                             <script>
  80.                                 setTimeout(function() {
  81.                                     window.location.href = "/";
  82.                                 }, 2000);
  83.                             </script>
  84.                         </body>
  85.                         </html>
  86.                     ''')
  87.             else:
  88.                 self.send_response(400)
  89.                 self.send_header('Content-type', 'text/html')
  90.                 self.end_headers()
  91.                 self.wfile.write(b'''
  92.                     <html>
  93.                     <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  94.                     <body>
  95.                         <p>Invalid content type.</p>
  96.                         <script>
  97.                             setTimeout(function() {
  98.                                 window.location.href = "/";
  99.                             }, 2000);
  100.                         </script>
  101.                     </body>
  102.                     </html>
  103.                 ''')
  104.         except Exception as e:
  105.             self.send_response(500)
  106.             self.send_header('Content-type', 'text/html')
  107.             self.end_headers()
  108.             self.wfile.write(f'''
  109.                 <html>
  110.                 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  111.                 <body>
  112.                     <p>Error occurred: {str(e)}</p>
  113.                     <script>
  114.                         setTimeout(function() {{
  115.                             window.location.href = "/";
  116.                         }}, 2000);
  117.                     </script>
  118.                 </body>
  119.                 </html>
  120.             '''.encode())
  121. def run(server_class=HTTPServer, handler_class=SimpleHTTPRequestHandler, port=8000):
  122.     server_address = ('', port)
  123.     httpd = server_class(server_address, handler_class)
  124.     # Uncomment the following lines if you need HTTPS support
  125.     # httpd.socket = ssl.wrap_socket(httpd.socket,
  126.     #                                keyfile="path/to/key.pem",
  127.     #                                certfile='path/to/cert.pem', server_side=True)
  128.     print(f'Starting httpd server on port {port}...')
  129.     httpd.serve_forever()
  130. if __name__ == '__main__':
  131.     run()
复制代码
在上述代码中,
  1. CustomFileHandler
复制代码
类继承自之前定义的
  1. MyHandler
复制代码
类(或直接从
  1. http.server.SimpleHTTPRequestHandler
复制代码
继承,如果你没有重写
  1. translate_path
复制代码
方法的话)。我们重写了
  1. do_GET
复制代码
方法,以处理GET请求并定制响应头。

  • 首先,我们通过
    1. translate_path
    复制代码
    方法获取请求文件的实际路径。
  • 然后,我们检查该文件是否存在。
  • 如果文件存在,我们使用
    1. mimetypes.guess_type
    复制代码
    函数猜测文件的MIME类型,并设置相应的
    1. Content-type
    复制代码
    响应头。
  • 最后,我们打开文件,并使用
    1. copyfile
    复制代码
    方法将文件内容发送给客户端。
如果文件不存在,我们通过
  1. send_error
复制代码
方法返回404错误。
浏览器访问http://localhost:8000/
能看到下载列表

点击选择文件可以上传


2.3.2 运行服务器

将上述代码保存为一个
  1. .py
复制代码
文件,并替换
  1. DIRECTORY
复制代码
变量的值为你希望服务器处理的文件目录。然后,按照之前的步骤运行服务器。
现在,当你通过浏览器访问服务器上的文件时(例如,
  1. http://localhost:8080/example.pdf
复制代码
),浏览器将以下载的方式处理该文件,而不是尝试在浏览器中打开它。

三、安全性考虑

虽然
  1. http.server
复制代码
模块提供了一个快速搭建HTTP服务器的方法,但它在安全性方面存在一些局限性。例如,默认情况下,它会处理服务器上所有可读文件的请求,这可能会暴露敏感信息。
为了增强安全性,你可以:

  • 限制服务器的访问权限,例如,使用防火墙规则来限制只有特定的IP地址或网络才能访问服务器。
  • 创建一个白名单,仅允许访问白名单中指定的文件或目录。
  • 使用更安全的HTTP服务器框架,如Flask或Django,这些框架提供了更丰富的功能和更好的安全性支持。

四、总结

通过本教程,我们学习了如何使用Python的
  1. http.server
复制代码
模块搭建一个基本的HTTP服务器,并实现文件下载服务。我们介绍了如何设置服务器端口、自定义文件目录、定制HTTP响应头以及处理GET请求。最后,我们还讨论了使用
  1. http.server
复制代码
模块时需要注意的一些安全性问题。希望这些内容对你有所帮助!
到此这篇关于通过Python中的http.server搭建文件上传下载服务功能的文章就介绍到这了,更多相关Python http.server文件上传下载服务内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

来源:https://www.jb51.net/python/326518bmi.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具