Python中如何实现一个简单的图片上传存储服务

七牛什么的自定义域名竟然还需要备案,所以花两天时间写了一个简单的图片上传存储服务(基于 flask)

示例,使用 requests上传图片

import requests

def images(): url = ‘http://127.0.0.1:8000/api/images’ files = {‘images’: open(‘desktop.png’, ‘rb’)} multiple_files = [ (‘images’, (‘11.png’, open(‘11.png’, ‘rb’), ‘image/png’)), (‘images’, (‘desktop.png’, open(‘desktop.png’, ‘rb’), ‘image/png’)) ] headers = { ‘Api-Key’: ‘InhpeWFuZzA4MDdJBtx4AWlPpI_Oxx1Ki8’, ‘User-Agent’: ‘Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.98 Safari/537.36’ } # r = requests.post(url, files=multiple_files, headers=headers) r = requests.post(url, files=files, headers=headers) print(r.text)

GitHub 地址: https://github.com/honmaple/maple-file


Python中如何实现一个简单的图片上传存储服务

7 回复

支持自动多尺寸 thumbnail 不?


我来给你一个完整的实现方案。这个服务会包含一个简单的Flask后端,用于接收图片并保存到本地,同时提供一个上传页面。

import os
from flask import Flask, request, render_template, jsonify
from werkzeug.utils import secure_filename

app = Flask(__name__)

# 配置
UPLOAD_FOLDER = 'uploads'  # 上传文件保存的目录
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif', 'bmp'}  # 允许的文件类型
MAX_CONTENT_LENGTH = 16 * 1024 * 1024  # 最大文件大小:16MB

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = MAX_CONTENT_LENGTH

# 确保上传目录存在
os.makedirs(UPLOAD_FOLDER, exist_ok=True)

def allowed_file(filename):
    """检查文件扩展名是否合法"""
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/')
def index():
    """显示上传页面"""
    return render_template('upload.html')

@app.route('/upload', methods=['POST'])
def upload_file():
    """处理文件上传"""
    # 检查是否有文件被上传
    if 'file' not in request.files:
        return jsonify({'error': '没有选择文件'}), 400
    
    file = request.files['file']
    
    # 检查是否选择了文件
    if file.filename == '':
        return jsonify({'error': '没有选择文件'}), 400
    
    # 检查文件类型
    if not allowed_file(file.filename):
        return jsonify({'error': '不支持的文件类型'}), 400
    
    # 安全处理文件名
    filename = secure_filename(file.filename)
    
    # 生成唯一文件名(避免重名)
    import uuid
    unique_filename = f"{uuid.uuid4().hex}_{filename}"
    
    # 保存文件
    file_path = os.path.join(app.config['UPLOAD_FOLDER'], unique_filename)
    file.save(file_path)
    
    return jsonify({
        'success': True,
        'filename': unique_filename,
        'original_name': filename,
        'url': f'/uploads/{unique_filename}'
    })

@app.route('/uploads/<filename>')
def uploaded_file(filename):
    """提供已上传文件的访问"""
    from flask import send_from_directory
    return send_from_directory(app.config['UPLOAD_FOLDER'], filename)

if __name__ == '__main__':
    app.run(debug=True)

还需要创建一个HTML模板文件 templates/upload.html

<!DOCTYPE html>
<html>
<head>
    <title>图片上传服务</title>
    <style>
        body { font-family: Arial; max-width: 600px; margin: 50px auto; }
        .upload-form { border: 2px dashed #ccc; padding: 30px; text-align: center; }
        .file-input { margin: 20px 0; }
        .preview { max-width: 300px; margin-top: 20px; display: none; }
        .result { margin-top: 20px; padding: 10px; }
    </style>
</head>
<body>
    <h2>图片上传服务</h2>
    
    <div class="upload-form">
        <form id="uploadForm" enctype="multipart/form-data">
            <input type="file" id="fileInput" class="file-input" accept="image/*">
            <br>
            <button type="submit">上传图片</button>
        </form>
        
        <img id="preview" class="preview" alt="图片预览">
        
        <div id="result" class="result"></div>
    </div>

    <script>
        document.getElementById('fileInput').addEventListener('change', function(e) {
            const file = e.target.files[0];
            if (file) {
                const reader = new FileReader();
                reader.onload = function(e) {
                    const preview = document.getElementById('preview');
                    preview.src = e.target.result;
                    preview.style.display = 'block';
                }
                reader.readAsDataURL(file);
            }
        });

        document.getElementById('uploadForm').addEventListener('submit', async function(e) {
            e.preventDefault();
            
            const fileInput = document.getElementById('fileInput');
            const formData = new FormData();
            formData.append('file', fileInput.files[0]);
            
            const resultDiv = document.getElementById('result');
            resultDiv.innerHTML = '上传中...';
            
            try {
                const response = await fetch('/upload', {
                    method: 'POST',
                    body: formData
                });
                
                const data = await response.json();
                
                if (data.success) {
                    resultDiv.innerHTML = `
                        <strong>上传成功!</strong><br>
                        文件名: ${data.filename}<br>
                        <a href="${data.url}" target="_blank">查看图片</a>
                    `;
                } else {
                    resultDiv.innerHTML = `<strong>错误:</strong> ${data.error}`;
                }
            } catch (error) {
                resultDiv.innerHTML = `<strong>上传失败:</strong> ${error.message}`;
            }
        });
    </script>
</body>
</html>

安装依赖:

pip install flask

运行服务:

python app.py

然后访问 http://localhost:5000 就能看到上传页面了。

这个实现包含了:

  1. 文件类型和大小验证
  2. 安全的文件名处理
  3. 唯一文件名生成(避免冲突)
  4. 前端预览功能
  5. 简单的REST API接口

如果需要更复杂的存储(比如数据库记录、云存储),可以在此基础上扩展。

总结:用Flask处理上传,注意安全验证和文件管理。

目前只是保存原图及生成 width=300 的缩略图,后续可能会加上

现在可以使用 url/40965530537.png?width=300&height=100,不过只支持等比缩放

自己架一个图片处理的服务也容易,有开源的一些解决方案可参考,稍作改动可以达到类似于七牛自定义后缀规则的效果 https://github.com/agschwender/pilbox

七牛不是有 api 么 直接上传不就好了~~~

是因为自定义域名要备案才自己写的

回到顶部