杰瑞科技汇

Python webservice 上传如何实现?

我们将使用 Python 最流行的 Web 框架 Flask 来实现,因为它轻量、简单且非常适合这类任务,我也会提供一个使用 FastAPI 的示例,因为它的性能更好,并且对异步支持更友好。

Python webservice 上传如何实现?-图1
(图片来源网络,侵删)

使用 Flask (简单、易上手)

Flask 是一个微框架,非常适合快速构建 Web 应用和 API。

安装 Flask

你需要安装 Flask,如果你还没有安装,可以通过 pip 来安装:

pip install Flask

创建上传目录

在你的项目文件夹下,创建一个用于存储上传文件的目录,uploads

/my_project
├── app.py
└── uploads/

确保 uploads 目录存在,并且你的 Web 服务器进程对该目录有写入权限。

Python webservice 上传如何实现?-图2
(图片来源网络,侵删)

编写 Flask Web 服务代码 (app.py)

下面是一个完整的、可运行的 Flask 应用示例,它包含一个用于上传文件的 HTML 表单和一个处理文件上传的后端 API。

# app.py
from flask import Flask, request, render_template, redirect, url_for
import os
# 创建 Flask 应用实例
app = Flask(__name__)
# 配置上传文件的目录
# 使用绝对路径或确保相对于脚本的路径是正确的
UPLOAD_FOLDER = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'uploads')
# 确保上传目录存在
if not os.path.exists(UPLOAD_FOLDER):
    os.makedirs(UPLOAD_FOLDER)
# 配置允许的文件扩展名
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
# Flask 应用配置
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 限制上传文件大小为 16MB
# 辅助函数:检查文件扩展名是否合法
def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
# 主页 - 显示上传表单
@app.route('/', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        # 检查是否有文件在请求中
        if 'file' not in request.files:
            flash('No file part')
            return redirect(request.url)
        file = request.files['file']
        # 如果用户没有选择文件,浏览器也会提交一个空的文件部分
        if file.filename == '':
            flash('No selected file')
            return redirect(request.url)
        # 如果文件合法,则保存
        if file and allowed_file(file.filename):
            # 为了防止文件名冲突,可以生成一个安全的文件名
            # 或者直接使用原始文件名
            filename = file.filename
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            return redirect(url_for('upload_file', filename=filename))
    # GET 请求时,显示上传页面
    # 这里我们简单返回一个提示,实际项目中可以渲染一个HTML模板
    return '''
    <!doctype html>Upload new File</title>
    <h1>Upload new File</h1>
    <form method=post enctype=multipart/form-data>
      <input type=file name=file>
      <input type=submit value=Upload>
    </form>
    '''
# 用于显示上传成功信息的路由 (可选)
@app.route('/uploads/<filename>')
def uploaded_file(filename):
    return f'File {filename} has been uploaded successfully!'
if __name__ == '__main__':
    # 在开发环境中运行,生产环境应使用 Gunicorn 或 uWSGI
    app.run(debug=True, host='0.0.0.0', port=5000)

运行服务

在终端中,导航到你的项目目录 (my_project),然后运行:

python app.py

你会看到类似下面的输出:

 * Serving Flask app 'app'
 * Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: ...

测试上传

  1. 打开浏览器,访问 http://127.0.0.1:5000
  2. 你会看到一个文件选择框和一个“Upload”按钮。
  3. 选择一个文件(test.jpg),然后点击上传。
  4. 文件会被保存到你项目下的 uploads 文件夹中。
  5. 页面会重定向,并显示上传成功的消息。

使用 FastAPI (现代、高性能、自动文档)

FastAPI 是一个现代、快速的(高性能)Web 框架,用于构建 API,它基于 Starlette 和 Pydantic,并且自动生成交互式 API 文档。

安装 FastAPI 和 Uvicorn

pip install "fastapi[all]"

[all] 会自动安装 uvicorn(ASGI 服务器)和 python-multipart(用于处理表单数据)。

创建上传目录

和 Flask 一样,创建一个 uploads 目录。

编写 FastAPI 服务代码 (main.py)

# main.py
import os
import shutil
from fastapi import FastAPI, UploadFile, File, HTTPException
from fastapi.responses import HTMLResponse
app = FastAPI()
# 配置上传目录
UPLOAD_DIRECTORY = os.path.join(os.path.dirname(os.path.abspath(__file__)), "uploads")
if not os.path.exists(UPLOAD_DIRECTORY):
    os.makedirs(UPLOAD_DIRECTORY)
# 定义允许的文件类型
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}
def allowed_file(filename: str):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile = File(...)):
    """
    接收单个文件上传
    """
    # 检查文件类型
    if not allowed_file(file.filename):
        raise HTTPException(status_code=400, detail="File type not allowed")
    # 构建文件保存路径
    file_location = os.path.join(UPLOAD_DIRECTORY, file.filename)
    # 使用 async 将文件内容写入磁盘
    try:
        with open(file_location, "wb") as buffer:
            shutil.copyfileobj(file.file, buffer)
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Could not save file: {e}")
    return {"info": f"file '{file.filename}' saved at '{file_location}'"}
@app.post("/uploadfiles/")
async def create_upload_files(files: list[UploadFile] = File(...)):
    """
    接收多个文件上传
    """
    info = []
    for file in files:
        if not allowed_file(file.filename):
            # 可以选择跳过或报错,这里我们跳过并记录
            info.append(f"Skipped invalid file: {file.filename}")
            continue
        file_location = os.path.join(UPLOAD_DIRECTORY, file.filename)
        try:
            with open(file_location, "wb") as buffer:
                shutil.copyfileobj(file.file, buffer)
            info.append(f"file '{file.filename}' saved at '{file_location}'")
        except Exception as e:
            info.append(f"Could not save file {file.filename}: {e}")
    return {"info": info}
@app.get("/", response_class=HTMLResponse)
async def main():
    """
    提供一个简单的HTML上传页面
    """
    return """
    <html>
        <head>
            <title>File Upload</title>
        </head>
        <body>
            <h1>Upload a file</h1>
            <form action="/uploadfile/" enctype="multipart/form-data" method="post">
                <input name="file" type="file">
                <input type="submit">
            </form>
            <h2>Or upload multiple files</h2>
            <form action="/uploadfiles/" enctype="multipart/form-data" method="post">
                <input name="files" type="file" multiple>
                <input type="submit">
            </form>
        </body>
    </html>
    """
if __name__ == "__main__":
    import uvicorn
    uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True)

运行服务

uvicorn main:app --reload

--reload 参数会在代码变更时自动重启服务器,方便开发。

测试上传和 API 文档

  1. API 文档: 打开浏览器访问 http://127.0.0.1:8000/docs,你会看到由 Swagger UI 生成的交互式 API 文档。
  2. HTML 上传页面: 访问 http://127.0.0.1:8000/,你可以像使用 Flask 示例一样通过网页上传文件。
  3. API 上传: 你也可以使用 curl 或 Postman 等工具
分享:
扫描分享到社交APP
上一篇
下一篇