首页
学习
活动
专区
圈层
工具
发布

使用纯AJAX/JS和Django上传文件

使用纯AJAX/JS和Django上传文件

基础概念

文件上传是现代Web应用中常见的功能,使用纯AJAX/JS和Django实现可以实现无刷新上传体验。这种方式避免了传统表单提交导致的页面刷新,提升了用户体验。

实现方案

前端实现 (JavaScript/AJAX)

代码语言:txt
复制
<!-- HTML部分 -->
<input type="file" id="fileInput">
<button onclick="uploadFile()">上传文件</button>
<div id="progressBar"></div>
<div id="status"></div>

<script>
function uploadFile() {
    const fileInput = document.getElementById('fileInput');
    const file = fileInput.files[0];
    
    if (!file) {
        alert('请选择文件');
        return;
    }
    
    const formData = new FormData();
    formData.append('file', file);
    formData.append('csrfmiddlewaretoken', getCookie('csrftoken'));
    
    const xhr = new XMLHttpRequest();
    
    // 上传进度事件
    xhr.upload.addEventListener('progress', function(e) {
        if (e.lengthComputable) {
            const percent = (e.loaded / e.total) * 100;
            document.getElementById('progressBar').innerHTML = 
                `上传进度: ${percent.toFixed(2)}%`;
        }
    });
    
    // 上传完成事件
    xhr.addEventListener('load', function(e) {
        if (xhr.status === 200) {
            const response = JSON.parse(xhr.responseText);
            document.getElementById('status').innerHTML = 
                `上传成功: ${response.message}`;
        } else {
            document.getElementById('status').innerHTML = 
                '上传失败: ' + xhr.statusText;
        }
    });
    
    // 上传错误事件
    xhr.addEventListener('error', function() {
        document.getElementById('status').innerHTML = '上传出错';
    });
    
    xhr.open('POST', '/upload/', true);
    xhr.send(formData);
}

// 获取CSRF token的函数
function getCookie(name) {
    let cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        const cookies = document.cookie.split(';');
        for (let i = 0; i < cookies.length; i++) {
            const cookie = cookies[i].trim();
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
</script>

后端实现 (Django)

代码语言:txt
复制
# views.py
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.core.files.storage import default_storage
import os

@csrf_exempt  # 仅用于测试,生产环境应使用CSRF保护
def upload_file(request):
    if request.method == 'POST':
        file = request.FILES.get('file')
        if not file:
            return JsonResponse({'error': '未接收到文件'}, status=400)
        
        try:
            # 保存文件到指定位置
            file_path = os.path.join('uploads', file.name)
            file_name = default_storage.save(file_path, file)
            
            return JsonResponse({
                'message': '文件上传成功',
                'file_path': file_name,
                'file_size': file.size,
                'file_type': file.content_type
            })
        except Exception as e:
            return JsonResponse({'error': str(e)}, status=500)
    
    return JsonResponse({'error': '仅支持POST请求'}, status=405)

URL配置

代码语言:txt
复制
# urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('upload/', views.upload_file, name='upload_file'),
]

优势

  1. 无刷新体验:用户上传文件时页面不会刷新,提升用户体验
  2. 进度反馈:可以实时显示上传进度
  3. 异步处理:不会阻塞用户界面操作
  4. 灵活性:可以轻松添加额外的表单数据或自定义请求头

常见问题及解决方案

1. CSRF验证失败

原因:Django默认启用CSRF保护,AJAX请求需要包含CSRF token

解决方案

  • 从cookie中获取CSRF token并添加到请求中(如示例代码所示)
  • 或者使用@csrf_exempt装饰器(仅限测试环境)

2. 文件大小限制

原因:Django默认有2.5MB的文件上传大小限制

解决方案

代码语言:txt
复制
# settings.py
DATA_UPLOAD_MAX_MEMORY_SIZE = 10485760  # 10MB
FILE_UPLOAD_MAX_MEMORY_SIZE = 10485760   # 10MB

3. 文件类型限制

解决方案:在前端和后端都进行验证

前端验证:

代码语言:txt
复制
// 检查文件类型
const allowedTypes = ['image/jpeg', 'image/png', 'application/pdf'];
if (!allowedTypes.includes(file.type)) {
    alert('不支持的文件类型');
    return;
}

后端验证:

代码语言:txt
复制
ALLOWED_EXTENSIONS = ['jpg', 'jpeg', 'png', 'pdf']

extension = file.name.split('.')[-1].lower()
if extension not in ALLOWED_EXTENSIONS:
    return JsonResponse({'error': '不支持的文件类型'}, status=400)

4. 大文件上传问题

解决方案:分片上传

代码语言:txt
复制
// 分片上传示例
function uploadInChunks(file) {
    const chunkSize = 1024 * 1024; // 1MB
    let offset = 0;
    
    function uploadNextChunk() {
        const chunk = file.slice(offset, offset + chunkSize);
        const formData = new FormData();
        formData.append('chunk', chunk);
        formData.append('filename', file.name);
        formData.append('offset', offset);
        formData.append('totalSize', file.size);
        
        const xhr = new XMLHttpRequest();
        xhr.open('POST', '/upload_chunk/', true);
        xhr.onload = function() {
            if (xhr.status === 200) {
                offset += chunkSize;
                if (offset < file.size) {
                    uploadNextChunk();
                } else {
                    console.log('上传完成');
                }
            }
        };
        xhr.send(formData);
    }
    
    uploadNextChunk();
}

应用场景

  1. 用户头像上传
  2. 文档管理系统
  3. 图片/视频分享平台
  4. 云存储服务
  5. 数据导入功能

进阶优化

  1. 文件预览:上传前显示缩略图
  2. 多文件上传:支持一次选择多个文件
  3. 断点续传:记录上传进度,支持中断后继续
  4. 文件校验:MD5校验确保文件完整性
  5. 响应式设计:适配不同设备
页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

没有搜到相关的文章

领券