Search Posts

python3构建http文件上传服务器

内容纲要

需求原因

机器需要上传文件到服务器,sftp经常失败,改为http上传测试

python代码

vim uploadfile.py
其中 /tmp改为你要写入的根目录
USERNAME PASSWORD参数值改为复杂一点的账号密码

import http.server
import socketserver
import os
import threading
import base64
import pwd
import grp

PORT = 8107  # 选择一个空闲端口
DIRECTORY = "/tmp"  # 文件存储根目录
USERNAME = "user"  # 设置用户名
PASSWORD = "password"  # 设置密码
OWNER = "datauser1"  # 设置文件所有者
GROUP = "datagroup1"  # 设置文件用户组

# 自定义请求处理类
class SimpleHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
    def do_POST(self):
        self.handle_upload()

    def do_PUT(self):
        self.handle_upload()

    def handle_upload(self):
        # 验证用户名和密码
        if not self.authenticate():
            self.send_response(401)
            self.send_header('WWW-Authenticate', 'Basic realm="File Upload"')
            self.end_headers()
            return

        # 解析请求,获取文件信息
        length = int(self.headers['Content-Length'])
        filename = os.path.basename(self.path)
        directory = os.path.dirname(self.path)
        path = os.path.join(DIRECTORY, directory[1:], filename)

        # 逐级创建多级目录并设置权限
        current_dir = DIRECTORY
        for dir_name in directory.split('/'):
            if dir_name:
                current_dir = os.path.join(current_dir, dir_name)
                os.makedirs(current_dir, exist_ok=True)
                os.chown(current_dir, pwd.getpwnam(OWNER).pw_uid, grp.getgrnam(GROUP).gr_gid)

        # 写入文件
        with open(path, 'wb') as f:
            f.write(self.rfile.read(length))

        # 获取所有者对应的UID和用户组对应的GID
        uid = pwd.getpwnam(OWNER).pw_uid
        gid = grp.getgrnam(GROUP).gr_gid

        # 更改文件所有者和用户组
        os.chown(path, uid, gid)  # 设置所有者为OWNER对应的UID,用户组为GROUP对应的GID

        self.send_response(200)
        self.end_headers()

    def authenticate(self):
        # 获取Authorization头部的值
        auth_header = self.headers.get('Authorization')
        if auth_header:
            # 解码用户名和密码
            auth_bytes = base64.b64decode(auth_header.split(' ')[1])
            auth_str = auth_bytes.decode('utf-8')
            # 检查用户名和密码是否匹配
            username, password = auth_str.split(':')
            return username == USERNAME and password == PASSWORD
        return False

# 创建HTTP服务器,使用ThreadingMixIn实现并发处理
class ThreadedHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
    pass

# 创建并启动HTTP服务器
with ThreadedHTTPServer(("", PORT), SimpleHTTPRequestHandler) as httpd:
    print("服务器已启动,端口号:", PORT)
    # 持续运行服务器
    httpd.serve_forever()

启动

当前终端运行

python3 uploadfile.py

后台运行

nohup python3 uploadfile.py >dev/null 2>&1 &

开机运行

要将Python脚本添加为CentOS 7的开机启动项,您可以创建一个Systemd服务单元文件。下面是一个简单的步骤:

  1. 创建一个新的Systemd服务单元文件。打开终端并键入以下命令:
sudo vim /etc/systemd/system/uploadfile.service
  1. 在编辑器中,添加以下内容:
[Unit]
Description=Upload File Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /root/scropts/uploadfile.py
Restart=on-failure

[Install]
WantedBy=multi-user.target

确保将 ExecStart 的路径指向您的Python解释器和脚本位置。

  1. 保存并关闭文件。

  2. 使用以下命令重新加载Systemd管理的服务单元列表,以使新添加的服务生效:

sudo systemctl daemon-reload
  1. 现在您可以启动、停止、重启和查看服务状态了:
  • 启动服务:
sudo systemctl start uploadfile
  • 停止服务:
sudo systemctl stop uploadfile
  • 重启服务:
sudo systemctl restart uploadfile
  • 查看服务状态:
sudo systemctl status uploadfile
  1. 如果您希望脚本在系统启动时自动启动,可以使用以下命令:
sudo systemctl enable uploadfile

现在,您的Python脚本将在系统启动时自动运行。

测试命令

支持PUT 或 POST 提交文件

curl -X PUT --user user:password --data-binary "@D:\WorkFile\x.txt" http://192.168.0.11:8000/mps/H30/y.txt
curl -X POST --user user:password --data-binary "@D:\WorkFile\x.txt" http://192.168.0.11:8000/mps/H30/y.txt

这个命令实现是将本地D:\WorkFile\x.txt上传到写入服务器的 /tmp/mps/H30/y.txt ,如果目录/tmp/mps/H30/不存在将自动创建

English version

Building an HTTP File Upload Server with Python 3

Reason for Requirement

The machine needs to upload files to the server. Since SFTP often fails, HTTP upload is tested as an alternative.

Python Code

Open a terminal and type the following command:

vim uploadfile.py

In the editor, add the following content. Replace /tmp with the root directory where you want to write, and change the USERNAME and PASSWORD parameter values to complex account passwords.

import http.server
import socketserver
import os
import threading
import base64
import pwd
import grp

PORT = 8107  # Select an available port
DIRECTORY = "/tmp"  # Root directory for file storage
USERNAME = "user"  # Set the username
PASSWORD = "password"  # Set the password
OWNER = "datauser1"  # Set the file owner
GROUP = "datagroup1"  # Set the file group

# Custom request handler class
class SimpleHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
    def do_POST(self):
        self.handle_upload()

    def do_PUT(self):
        self.handle_upload()

    def handle_upload(self):
        # Authenticate username and password
        if not self.authenticate():
            self.send_response(401)
            self.send_header('WWW-Authenticate', 'Basic realm="File Upload"')
            self.end_headers()
            return

        # Parse the request and get file information
        length = int(self.headers['Content-Length'])
        filename = os.path.basename(self.path)
        directory = os.path.dirname(self.path)
        path = os.path.join(DIRECTORY, directory[1:], filename)

        # Create multiple directories and set permissions
        current_dir = DIRECTORY
        for dir_name in directory.split('/'):
            if dir_name:
                current_dir = os.path.join(current_dir, dir_name)
                os.makedirs(current_dir, exist_ok=True)
                os.chown(current_dir, pwd.getpwnam(OWNER).pw_uid, grp.getgrnam(GROUP).gr_gid)

        # Write the file
        with open(path, 'wb') as f:
            f.write(self.rfile.read(length))

        # Get UID and GID corresponding to owner and group
        uid = pwd.getpwnam(OWNER).pw_uid
        gid = grp.getgrnam(GROUP).gr_gid

        # Change file owner and group
        os.chown(path, uid, gid)  # Set owner to UID of OWNER, group to GID of GROUP

        self.send_response(200)
        self.end_headers()

    def authenticate(self):
        # Get value of Authorization header
        auth_header = self.headers.get('Authorization')
        if auth_header:
            # Decode username and password
            auth_bytes = base64.b64decode(auth_header.split(' ')[1])
            auth_str = auth_bytes.decode('utf-8')
            # Check if username and password match
            username, password = auth_str.split(':')
            return username == USERNAME and password == PASSWORD
        return False

# Create HTTP server with ThreadingMixIn for concurrent handling
class ThreadedHTTPServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
    pass

# Create and start HTTP server
with ThreadedHTTPServer(("", PORT), SimpleHTTPRequestHandler) as httpd:
    print("Server started on port:", PORT)
    # Keep the server running
    httpd.serve_forever()

Start

Run in the current terminal

python3 uploadfile.py

Run in the background

nohup python3 uploadfile.py >/dev/null 2>&1 &

Run at startup

To add the Python script as a startup item in CentOS 7, you can create a Systemd service unit file. Here are the steps:

  1. Create a new Systemd service unit file. Open a terminal and type the following command:
sudo vim /etc/systemd/system/uploadfile.service
  1. In the editor, add the following content:
[Unit]
Description=Upload File Service
After=network.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /root/scropts/uploadfile.py
Restart=on-failure

[Install]
WantedBy=multi-user.target

Make sure to replace the path in ExecStart with the location of your Python interpreter and script.

  1. Save and close the file.

  2. Use the following command to reload the list of Systemd-managed service units to apply the changes:

sudo systemctl daemon-reload
  1. Now you can start, stop, restart, and view the status of the service:
  • Start the service:
sudo systemctl start uploadfile
  • Stop the service:
sudo systemctl stop uploadfile
  • Restart the service:
sudo systemctl restart uploadfile
  • View the service status:
sudo systemctl status uploadfile
  1. If you want the script to start automatically when the system boots, you can use the following command:
sudo systemctl enable uploadfile

Now, your Python script will run automatically when the system starts.

Test Command

PUT OR POST

curl -X PUT --user user:password --data-binary "@D:\WorkFile\x.txt" http://192.168.0.11:8000/mps/H30/y.txt
curl -X POST --user user:password --data-binary "@D:\WorkFile\x.txt" http://192.168.0.11:8000/mps/H30/y.txt

This command uploads the local file D:\WorkFile\x.txt to /tmp/mps/H30/y.txt on the server. If the directory /tmp/mps/H30/ does not exist, it will be created automatically.

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注