Django WiFi文件分享

内容分享3小时前发布
0 0 0

项目介绍

在日常工作和生活中,我们经常需要在电脑和手机之间传输文件。传统的传输方式要么需要数据线连接,要么需要借助第三方应用,操作繁琐且不够高效。今天,我将介绍一个基于Django开发的WiFi文件分享应用,它可以让你通过电脑选择本地文件夹,生成访问二维码,然后通过手机扫描二维码即可访问并下载文件,实现快速、便捷的文件共享。

功能特性

– 📁 **文件目录选择**:直观的文件夹选择器,支持浏览并选择本地电脑中的指定文件夹

– 📋 **文件列表展示**:完整显示目录下的所有内容,包括文件和子目录,清晰区分文件类型

– 📱 **手机自适应**:响应式设计,适配各种移动设备

– 📲 **二维码访问**:自动生成包含访问URL的二维码,手机扫描即可快速访问

– 💾 **文件下载**:支持各类常见文件格式的下载

– ⚡ **高性能**:支持大文件传输,文件列表分页加载

– 🔒 **安全可靠**:防止路径遍历攻击,文件大小限制,权限检查

技术栈选择

在开发这个应用时,我选择了以下技术栈:

– **后端框架**:Django 5.0.6 – 成熟稳定的Python Web框架,提供了丰富的内置功能

– **前端技术**:HTML5, CSS3, JavaScript – 基础的Web前端技术栈

– **UI框架**:Bootstrap 5.3.0 – 用于快速构建响应式页面

– **二维码生成**:qrcode库 – 用于在后端生成二维码图片

– **数据库**:SQLite – 轻量级数据库,适合开发和小型应用

核心功能实现

 1. 目录选择功能

实现思路

目录选择功能允许用户在电脑上选择一个本地文件夹作为分享目录。为了保证安全性,应用会对用户输入的目录路径进行验证,并转换为绝对路径以防止路径遍历攻击。

代码实现



```python
 
# file_share/views.py
 
def home(request):
 
    global SHARED_DIR
 
    if request.method == 'POST':
 
        selected_dir = request.POST.get('directory', '')
 
        try:
 
            # 验证目录是否存在且可访问
 
            if os.path.isdir(selected_dir):
 
                # 获取绝对路径以防止相对路径攻击
 
                abs_path = os.path.abspath(selected_dir)
 
                SHARED_DIR = abs_path
 
                return JsonResponse({'success': True, 'message': '目录选择成功'})
 
            else:
 
                return JsonResponse({'success': False, 'message': '无效的目录路径或无法访问'})
 
        except PermissionError:
 
            return JsonResponse({'success': False, 'message': '没有权限访问该目录'})
 
        except Exception as e:
 
            return JsonResponse({'success': False, 'message': f'发生错误: {str(e)}'})
 
```

2. 文件列表展示

实现思路

文件列表展示功能用于获取并显示分享目录中的文件和子目录。应用使用`os.scandir()`函数高效遍历目录,并对结果进行分页处理,以提高性能和用户体验。



#### 代码实现
 
 
 
```python
 
# file_share/views.py
 
def file_list(request):
 
    global SHARED_DIR
 
    shared_dir = SHARED_DIR
 
    if not shared_dir:
 
        return JsonResponse({'error': '未选择分享目录'})
 
   
 
    # 处理分页参数
 
    page = int(request.GET.get('page', 1))
 
    page_size = int(request.GET.get('page_size', 50))  # 默认每页显示50个文件
 
    offset = (page - 1) * page_size
 
   
 
    files = []
 
    total = 0
 
    try:
 
        entries = os.scandir(shared_dir)
 
        for entry in entries:
 
            try:
 
                file_info = {
 
                    'name': entry.name,
 
                    'is_dir': entry.is_dir(),
 
                    'path': os.path.relpath(entry.path, shared_dir),
 
                    'size': entry.stat().st_size if entry.is_file() else 0,
 
                    'mtime': entry.stat().st_mtime
 
                }
 
                files.append(file_info)
 
                total += 1
 
            except PermissionError:
 
                # 跳过没有权限访问的文件/目录
 
                continue
 
            except Exception as e:
 
                # 记录错误但继续处理其他文件
 
                continue
 
       
 
        # 分页处理 - 保持文件系统原始顺序
 
        paginated_files = files[offset:offset + page_size]
 
       
 
        return JsonResponse({
 
            'files': paginated_files,
 
            'total': total,
 
            'page': page,
 
            'page_size': page_size,
 
            'total_pages': (total + page_size - 1) // page_size
 
        })
 
    except PermissionError:
 
        return JsonResponse({'error': '没有权限访问该目录'})
 
    except Exception as e:
 
        return JsonResponse({'error': f'目录访问错误: {str(e)}'})
 
```

 3. 二维码生成

实现思路

二维码生成功能用于生成包含访问URL的二维码图片。为了确保手机能够正确访问,应用使用了实际的本地IP地址而非localhost,并使用qrcode库在后端生成二维码图片。



#### 代码实现
 
 
 
```python
 
# file_share/views.py
 
def get_local_ip():
 
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
 
    try:
 
        s.connect(('8.8.8.8', 80))
 
        ip = s.getsockname()[0]
 
    finally:
 
        s.close()
 
    return ip
 
 
 
def qrcode_generator(request):
 
    """生成二维码图片"""
 
    try:
 
        # 使用实际本地IP地址,确保手机可以访问
 
        protocol = request.scheme
 
        hostname = get_local_ip()  # 使用实际本地IP地址
 
        port = request.get_port()
 
        url = f"{protocol}://{hostname}:{port}/"
 
       
 
        # 生成二维码
 
        qr = qrcode.QRCode(
 
            version=1,
 
            error_correction=qrcode.constants.ERROR_CORRECT_H,
 
            box_size=10,
 
            border=4,
 
        )
 
        qr.add_data(url)
 
        qr.make(fit=True)
 
       
 
        img = qr.make_image(fill_color="black", back_color="white")
 
       
 
        # 将图片转换为HTTP响应
 
        buffer = BytesIO()
 
        img.save(buffer, format="PNG")
 
        buffer.seek(0)
 
       
 
        response = HttpResponse(buffer.getvalue(), content_type="image/png")
 
        response["Content-Disposition"] = "inline; filename=qrcode.png"
 
        return response
 
    except Exception as e:
 
        return HttpResponse(f"二维码生成失败: {str(e)}", status=500)
 
```

 4. 文件下载

实现思路

文件下载功能用于将电脑上的文件下载到手机。为了支持大文件下载并提高性能,应用使用了Django的`FileResponse`类,它支持流式传输,不需要将整个文件加载到内存中。



#### 代码实现
 
 
 
```python
 
# file_share/views.py
 
# 设置最大文件下载大小为10GB
 
MAX_DOWNLOAD_SIZE = 10 * 1024 * 1024 * 1024
 
 
 
def download_file(request, file_path):
 
    global SHARED_DIR
 
    shared_dir = SHARED_DIR
 
    if not shared_dir:
 
        return HttpResponse('未选择分享目录', status=400)
 
   
 
    try:
 
        # 防止路径遍历攻击
 
        file_path = uri_to_iri(file_path)
 
        full_path = os.path.join(shared_dir, file_path)
 
        full_path = os.path.abspath(full_path)
 
       
 
        # 确保文件在分享目录内
 
        if not full_path.startswith(shared_dir):
 
            return HttpResponse('无效的文件路径', status=403)
 
       
 
        if not os.path.exists(full_path):
 
            return HttpResponse('文件不存在', status=404)
 
       
 
        if os.path.isdir(full_path):
 
            return HttpResponse('不能下载目录', status=400)
 
       
 
        # 检查文件大小
 
        file_size = os.path.getsize(full_path)
 
        if file_size > MAX_DOWNLOAD_SIZE:
 
            return HttpResponse(f'文件大小超过限制 ({MAX_DOWNLOAD_SIZE / (1024*1024):.1f}MB)', status=413)
 
       
 
        # 使用Django的FileResponse来处理文件下载,这是Django推荐的方式
 
        from django.http import FileResponse
 
        response = FileResponse(open(full_path, 'rb'), as_attachment=True)
 
        response['Content-Disposition'] = f'attachment; filename="{os.path.basename(full_path)}"'
 
        response['Content-Length'] = str(file_size)
 
        return response
 
    except PermissionError:
 
        return HttpResponse('没有权限访问该文件', status=403)
 
    except FileNotFoundError:
 
        return HttpResponse('文件不存在', status=404)
 
    except Exception as e:
 
        return HttpResponse(f'下载失败: {str(e)}', status=500)
 
```

5. 设备适配

 实现思路

为了提供更好的用户体验,应用需要根据访问设备的类型调整UI。当用户使用手机访问时,应该隐藏目录选择区域,只显示二维码和文件列表,提供更简洁的界面。



#### 代码实现
 
 
 
```javascript
 
// 检测设备类型
 
function isMobileDevice() {
 
    const userAgent = navigator.userAgent || navigator.vendor || window.opera;
 
    // 检测是否为移动设备
 
    return (/android/i.test(userAgent) ||
 
            /iPad|iPhone|iPod/.test(userAgent) && !window.MSStream);
 
}
 
 
 
// 控制UI元素显示
 
function controlUI() {
 
    const isMobile = isMobileDevice();
 
    if (isMobile) {
 
        // 在手机端隐藏目录选择区域
 
        const dirSelectCard = document.querySelector('.card:nth-child(2)');
 
        if (dirSelectCard) {
 
            dirSelectCard.style.display = 'none';
 
        }
 
    }
 
}
 
 
 
// 初始化
 
ocument.addEventListener('DOMContentLoaded', () => {
 
    controlUI();
 
    {% if shared_dir %}
 
        loadFileList();
 
    {% endif %}
 
});
 
```

技术亮点

 1. 安全设计

– **防止路径遍历攻击**:在处理文件路径时,应用会将相对路径转换为绝对路径,并检查文件是否在分享目录内,防止恶意用户访问系统敏感文件

– **文件大小限制**:设置了最大文件下载大小限制,防止过大文件占用过多服务器资源

– **权限检查**:在访问文件和目录时,应用会检查当前用户是否有相应的权限

– **使用Django内置安全功能**:利用Django的CSRF保护、XSS防护等内置安全功能

 2. 性能优化

– **分页加载**:文件列表采用分页加载,避免一次性加载大量文件导致性能问题

– **流式传输**:使用FileResponse实现文件的流式传输,支持大文件下载,不需要将整个文件加载到内存中

– **异步请求**:使用JavaScript异步请求加载文件列表,提高页面响应速度

– **合理的错误处理**:在处理文件系统操作时,使用try-except块捕获异常,确保应用不会因为单个文件的问题而崩溃

 3. 移动端适配

– **响应式设计**:使用Bootstrap的响应式组件和CSS媒体查询,确保应用在不同屏幕尺寸的设备上都能正常显示

– **设备检测**:通过JavaScript检测访问设备类型,根据设备类型调整UI元素的显示

– **简化移动端界面**:在移动端隐藏不必要的UI元素,只显示核心功能,提供更简洁的用户体验

项目部署

开发环境部署

1. **安装依赖**



   ```bash
 
   pip install -r requirements.txt
 
   ```

2. **数据库迁移**

   “`bash

   python manage.py migrate

   “`

3. **启动开发服务器**

   “`bash

   python manage.py runserver 0.0.0.0:8000

   “`

   服务器将在 http://0.0.0.0:8000/ 上运行。

### 生产环境部署

对于生产环境,建议使用以下部署方案:

1. **使用Gunicorn作为WSGI服务器**

   “`bash

   pip install gunicorn

   gunicorn –bind 0.0.0.0:8000 wifi_share.wsgi

   “`

2. **使用Nginx作为反向代理**

   配置Nginx转发请求到Gunicorn:

   “`nginx

   server {

       listen 80;

       server_name example.com;

       

       location / {

           proxy_pass http://127.0.0.1:8000;

           proxy_set_header Host $host;

           proxy_set_header X-Real-IP $remote_addr;

           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

       }

   }

   “`

3. **使用systemd管理服务**

   创建systemd服务文件,确保应用在系统启动时自动运行:

   “`bash

   sudo nano /etc/systemd/system/wifi-share.service

   “`

   内容如下:

   “`

   [Unit]

   Description=WiFi File Share Django Application

   After=network.target

   

   [Service]

   User=your_username

   Group=www-data

   WorkingDirectory=/path/to/your/project

   ExecStart=/path/to/your/venv/bin/gunicorn –bind 0.0.0.0:8000 wifi_share.wsgi

   Restart=always

   

   [Install]

   WantedBy=multi-user.target

   “`

   启动服务:

   “`bash

   sudo systemctl start wifi-share

   sudo systemctl enable wifi-share

   “`

总结与展望

通过这个WiFi文件分享应用的开发,我们学习了如何使用Django框架开发一个实用的Web应用,包括目录选择、文件列表展示、二维码生成、文件下载等核心功能。同时,我们也学习了如何进行安全设计、性能优化和移动端适配,这些都是Web开发中的重要知识点。

未来改进方向

1. **添加文件上传功能**:允许从手机向电脑上传文件

2. **支持子目录浏览**:目前只能显示一级目录,未来可以添加子目录浏览功能

3. **添加文件搜索功能**:支持按文件名搜索文件

4. **添加用户认证**:支持多用户使用,每个用户可以创建自己的分享目录

5. **添加文件预览功能**:支持在浏览器中预览图片、文档等文件

6. **添加进度显示**:为文件下载添加进度条显示

这个应用虽然功能简单,但实用性强,代码结构清晰,适合作为Django学习的实践项目。希望通过本文的介绍,能够帮助大家更好地理解Django的开发流程和核心概念,同时也能够为大家开发类似的应用提供参考。

 参考资料

– [Django官方文档](https://docs.djangoproject.com/)

– [Bootstrap官方文档](https://getbootstrap.com/)

– [qrcode库文档](https://pypi.org/project/qrcode/)

– [Python文件操作教程](https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files)

Django WiFi文件分享

© 版权声明

相关文章

暂无评论

none
暂无评论...