Python Flask 构建局域网文件传输工具:HTTP服务器实战

发布时间:2026/8/8 6:30:43
Python Flask 构建局域网文件传输工具:HTTP服务器实战 在日常开发或团队协作中你是否遇到过这样的困扰需要快速将电脑上的一个文件传给旁边的同事却不想登录臃肿的聊天软件也不想折腾复杂的局域网共享设置或者临时需要从自己的手机向电脑发送几张截图却发现常用的传输工具要么捆绑广告要么速度慢如蜗牛如果你也为此烦恼那么本文将为你提供一个绝佳的解决方案。我们将使用Python从零开始打造一个干净、极简、无任何捆绑的本地文件互传工具。它基于 HTTP 协议无需安装任何客户端打开浏览器即可上传下载传输速度直接跑满你的局域网带宽堪称“超快文件分享”。本文将手把手带你完成从原理理解、环境搭建、代码编写到最终打包成可执行文件的完整流程。无论你是 Python 新手想做一个有趣的实战项目还是有一定经验的开发者希望学习网络编程和 GUI 开发都能从中获得清晰的指引和可复用的代码。1. 背景与核心概念为什么需要自建文件互传工具在深入代码之前我们有必要先厘清这个工具要解决的核心问题及其背后的技术原理。1.1 现有工具的痛点市面上并非没有文件传输工具但它们通常存在以下问题捆绑与广告许多免费工具在安装包中捆绑了其他软件或在界面中植入广告影响使用体验。依赖网络与账号如微信文件助手、网盘等需要互联网连接和账号登录且对文件大小、类型有限制。配置复杂Windows 网络共享或 FTP 服务配置步骤繁琐对非技术人员不友好。平台限制某些工具仅限特定操作系统或设备间使用。我们的目标是打造一个开箱即用、绿色免安装、纯本地网络、无任何多余功能的传输工具。1.2 核心技术原理HTTP 服务器本工具的核心原理非常简单将你的电脑临时变成一台 HTTP 文件服务器。服务端在发送文件的电脑上运行一个 Python 编写的 HTTP 服务器。这个服务器会暴露一个本地 IP 地址和端口如http://192.168.1.100:8000。客户端在同一局域网内的任何设备电脑、手机、平板上打开浏览器访问上述地址。传输浏览器中会显示一个文件上传界面和已共享的文件列表。用户可以通过网页上传文件到服务器或点击链接下载服务器上的文件。为什么选择 HTTP通用性HTTP 是 Web 的基础协议任何有浏览器的设备都支持。简单性Python 标准库http.server和第三方库如Flask可以轻松创建 HTTP 服务。无依赖无需在接收方安装任何特定软件。1.3 工具核心功能设计基于以上原理我们的工具需要实现以下功能一键启动/停止服务器通过图形界面或命令行简单控制。显示服务器地址自动获取本机在局域网中的 IP 地址并生成可访问的 URL。文件列表展示在网页上清晰展示指定共享目录下的所有文件。文件上传与下载提供网页表单用于上传文件每个文件提供下载链接。跨平台运行代码应能在 Windows、macOS、Linux 上运行。可执行文件打包最终打包成.exe(Windows) 或.app(macOS) 等让没有 Python 环境的用户也能使用。2. 环境准备与版本说明“工欲善其事必先利其器”。在开始编码前请确保你的开发环境已就绪。2.1 Python 环境本项目主要使用 Python 标准库但为了更好的用户体验和打包我们会用到少量第三方库。Python 版本推荐使用Python 3.7 及以上版本。本文示例基于 Python 3.9 编写但核心代码兼容性很高。检查版本在终端或命令行中输入python --version或python3 --version。包管理工具使用pip安装第三方库。2.2 开发工具与第三方库代码编辑器或 IDE任选其一即可。VS Code轻量级安装 Python 插件后体验很好。PyCharm功能强大的 Python 专属 IDE。Sublime Text / Atom 等。所需第三方库我们将使用Flask来构建更灵活强大的 Web 服务使用pyinstaller进行打包。Flask一个轻量级的 Web 应用框架比标准库的http.server更易于扩展和定制界面。pyinstaller将 Python 脚本打包成独立可执行文件的工具。安装命令pip install flask pyinstaller如果下载慢可以使用国内镜像源例如pip install flask pyinstaller -i https://pypi.tuna.tsinghua.edu.cn/simple2.3 项目结构预览在开始前我们先规划一下项目文件夹的结构这有助于理解代码组织fast_file_share/ ├── app.py # 主程序Flask 应用核心逻辑 ├── templates/ # 存放 HTML 模板文件 │ └── index.html # 主页面模板 ├── static/ # 存放静态资源CSS, JS可选 │ └── style.css # 样式表可选 ├── uploads/ # 文件上传的默认保存目录运行后自动创建 ├── requirements.txt # 项目依赖列表后续生成 └── README.md # 项目说明文档你可以先在本地创建一个名为fast_file_share的文件夹并按照上述结构创建子文件夹。3. 核心模块与原理拆解我们的应用主要包含两个核心部分后端 Flask 服务和前端 HTML 界面。后端处理文件列表、上传、下载的逻辑前端提供用户交互界面。3.1 后端核心Flask 应用 (app.py)Flask 是一个“微框架”核心简单但可通过扩展实现强大功能。我们主要用到它的路由、请求处理和模板渲染。路由定义了 URL 路径与处理函数之间的映射。例如访问根路径/时由index()函数处理。请求对象Flask 的request对象可以获取前端传来的数据如表单数据、文件等。模板渲染使用 Jinja2 模板引擎将后端的 Python 变量动态嵌入到 HTML 中。3.2 前端核心HTML 模板 (templates/index.html)前端页面需要实现以下功能显示服务器 IP 和端口信息。展示uploads文件夹下的文件列表每个文件附带下载链接和删除按钮。提供一个文件选择表单和上传按钮。可以手动输入端口并重启服务器进阶功能。我们将使用简单的 HTML 和 CSS 来构建界面并通过 Jinja2 模板语法接收后端传递的数据如文件列表。3.3 关键函数与流程获取本地 IP 地址需要自动获取电脑在局域网中的 IP而不是127.0.0.1localhost。我们会使用 Python 的socket库来实现。文件安全处理上传检查文件名合法性防止路径遍历攻击如../../../etc/passwd。保存使用secure_filename处理文件名并保存到指定目录。下载使用send_from_directory安全地发送文件。删除提供删除功能并确认操作。生成可访问链接将 IP 和端口组合成http://ip:port的格式并显示在页面上。4. 完整实战案例一步步构建文件分享工具接下来我们进入具体的代码实现环节。请跟随步骤创建对应的文件并写入代码。4.1 创建项目结构与基础文件首先创建项目根目录fast_file_share并在其中创建子文件夹和文件。mkdir fast_file_share cd fast_file_share mkdir templates static uploads touch app.py touch templates/index.html touch static/style.css # 可选用于美化4.2 编写后端核心代码app.py打开app.py写入以下完整代码。代码中包含了详细的注释请仔细阅读以理解每一部分的作用。# app.py import os import socket from flask import Flask, render_template, request, send_from_directory, redirect, url_for, jsonify from werkzeug.utils import secure_filename # 初始化 Flask 应用 app Flask(__name__) # 配置 UPLOAD_FOLDER uploads # 上传文件保存的目录 ALLOWED_EXTENSIONS {txt, pdf, png, jpg, jpeg, gif, zip, py, md, docx, xlsx} # 允许的文件类型可选为空则允许所有 app.config[UPLOAD_FOLDER] UPLOAD_FOLDER app.config[MAX_CONTENT_LENGTH] 500 * 1024 * 1024 # 限制上传大小为 500MB # 确保上传目录存在 os.makedirs(UPLOAD_FOLDER, exist_okTrue) def get_local_ip(): 获取本机在局域网中的 IP 地址 try: # 创建一个 UDP 套接字不需要真正连接 s socket.socket(socket.AF_INET, socket.SOCK_DGRAM) s.connect((8.8.8.8, 80)) # 连接一个外部地址 ip s.getsockname()[0] s.close() return ip except Exception: return 127.0.0.1 # 如果获取失败退回本地环回地址 def allowed_file(filename): 检查文件后缀是否在允许列表中 if not ALLOWED_EXTENSIONS: # 如果允许列表为空则允许所有文件 return True return . in filename and filename.rsplit(., 1)[1].lower() in ALLOWED_EXTENSIONS app.route(/) def index(): 主页显示文件列表和上传表单 # 获取上传目录下的所有文件 files [] for filename in os.listdir(app.config[UPLOAD_FOLDER]): filepath os.path.join(app.config[UPLOAD_FOLDER], filename) if os.path.isfile(filepath): # 只处理文件忽略子目录 files.append(filename) # 获取本地 IP local_ip get_local_ip() # 渲染模板传递文件列表和 IP 地址 return render_template(index.html, filesfiles, local_iplocal_ip) app.route(/upload, methods[POST]) def upload_file(): 处理文件上传 if file not in request.files: return redirect(request.url) file request.files[file] # 如果用户没有选择文件浏览器会提交一个空文件 if file.filename : return redirect(request.url) if file and allowed_file(file.filename): # 对文件名进行安全处理 filename secure_filename(file.filename) # 处理文件名冲突如果已存在则在文件名后添加序号 base, extension os.path.splitext(filename) counter 1 while os.path.exists(os.path.join(app.config[UPLOAD_FOLDER], filename)): filename f{base}_{counter}{extension} counter 1 # 保存文件 file.save(os.path.join(app.config[UPLOAD_FOLDER], filename)) return redirect(url_for(index)) else: return 文件类型不允许或上传出错, 400 app.route(/download/filename) def download_file(filename): 提供文件下载 # 使用 secure_filename 再次校验防止路径遍历 safe_filename secure_filename(filename) return send_from_directory(app.config[UPLOAD_FOLDER], safe_filename, as_attachmentTrue) app.route(/delete/filename, methods[POST]) def delete_file(filename): 删除指定文件 safe_filename secure_filename(filename) file_path os.path.join(app.config[UPLOAD_FOLDER], safe_filename) if os.path.exists(file_path): os.remove(file_path) return jsonify({success: True}) return jsonify({success: False, error: 文件不存在}), 404 app.route(/get_ip) def get_ip(): API 接口返回当前服务器的 IP 地址用于前端动态显示 return jsonify({ip: get_local_ip()}) if __name__ __main__: # 获取 IP 和设置端口 ip get_local_ip() port 5000 # 默认端口可以根据需要修改 print(f * 服务器即将启动在 http://{ip}:{port}) print(f * 请在同一局域网下的设备浏览器中访问上述地址) print(f * 上传目录: {os.path.abspath(UPLOAD_FOLDER)}) # 运行应用host0.0.0.0 表示监听所有网络接口 app.run(host0.0.0.0, portport, debugTrue)关键代码解释get_local_ip(): 通过连接一个外部 DNS 服务器 (8.8.8.8) 来获取本机有效的局域网 IP。secure_filename(): 来自werkzeug用于确保文件名安全移除路径分隔符等危险字符。app.route(): Flask 装饰器用于定义路由。render_template(): 渲染 HTML 模板并可以传递 Python 变量过去。send_from_directory(): 安全地从指定目录发送文件给客户端。app.run(host0.0.0.0): 这是关键0.0.0.0表示监听所有网络接口使得局域网内其他设备可以访问。如果使用默认的127.0.0.1则只有本机可以访问。4.3 编写前端 HTML 模板templates/index.html接下来创建前端页面。这是一个基础但功能完整的界面。!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title超快文件分享/title link relstylesheet href{{ url_for(static, filenamestyle.css) }} style /* 基础样式可放入单独的 style.css 文件 */ body { font-family: sans-serif; margin: 20px; background-color: #f5f5f5; } .container { max-width: 800px; margin: auto; background: white; padding: 30px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); } h1 { color: #333; text-align: center; } .server-info { background: #e7f3ff; padding: 15px; border-radius: 5px; margin-bottom: 20px; } .server-info code { font-size: 1.1em; background: #fff; padding: 2px 6px; border-radius: 3px; } .section { margin-bottom: 30px; } .file-list ul { list-style: none; padding: 0; } .file-list li { padding: 10px; border-bottom: 1px solid #eee; display: flex; justify-content: space-between; align-items: center; } .file-list li:hover { background-color: #f9f9f9; } .file-actions a { margin-left: 10px; text-decoration: none; padding: 5px 10px; border-radius: 3px; font-size: 0.9em; } .download-btn { background-color: #4CAF50; color: white; } .delete-btn { background-color: #f44336; color: white; cursor: pointer; border: none; } .upload-form input[typefile] { padding: 10px; } .upload-form input[typesubmit] { background-color: #008CBA; color: white; padding: 10px 20px; border: none; border-radius: 5px; cursor: pointer; } .note { font-size: 0.9em; color: #666; margin-top: 5px; } /style /head body div classcontainer h1 超快文件分享/h1 div classserver-info section h3服务器信息/h3 p请在 strong同一局域网(Wi-Fi)/strong 下的其他设备浏览器中访问/p pcode idserverUrl正在获取.../code/p p classnote如果无法访问请检查防火墙是否放行了端口 strong5000/strong。/p /div div classsection h3 上传新文件/h3 form classupload-form action{{ url_for(upload_file) }} methodpost enctypemultipart/form-data input typefile namefile required input typesubmit value开始上传 /form p classnote支持的文件类型常见图片、文档、压缩包等。单文件最大 500MB。/p /div div classfile-list section h3 已共享的文件列表 ({{ files|length }} 个)/h3 {% if files %} ul {% for file in files %} li span{{ file }}/span div classfile-actions a classdownload-btn href{{ url_for(download_file, filenamefile) }} download下载/a button classdelete-btn onclickdeleteFile({{ file }})删除/button /div /li {% endfor %} /ul {% else %} p暂无文件。请上传第一个文件。/p {% endif %} /div /div script // 页面加载后动态获取并显示服务器 IP fetch(/get_ip) .then(response response.json()) .then(data { const ip data.ip; const port window.location.port || 5000; // 默认端口 5000 const url http://${ip}:${port}; document.getElementById(serverUrl).textContent url; // 可选将链接变为可点击 document.getElementById(serverUrl).innerHTML a href${url} target_blank${url}/a; }) .catch(error { console.error(获取IP失败:, error); document.getElementById(serverUrl).textContent 获取失败请检查控制台; }); // 删除文件函数 function deleteFile(filename) { if (confirm(确定要删除文件 ${filename} 吗)) { fetch(/delete/${filename}, { method: POST }) .then(response response.json()) .then(data { if (data.success) { alert(文件删除成功); location.reload(); // 刷新页面更新列表 } else { alert(删除失败 (data.error || 未知错误)); } }) .catch(error { console.error(删除请求出错:, error); alert(网络请求失败请重试。); }); } } /script /body /html关键点说明{{ ... }}: 这是 Jinja2 模板语法用于嵌入后端传递的变量如files文件列表和local_ip。{% for file in files %}: 模板中的循环语句用于遍历文件列表并生成 HTML。{{ url_for(...) }}: Flask 提供的函数用于生成对应的 URL避免硬编码。JavaScript (fetch API): 用于动态获取服务器 IP (/get_ip接口) 和处理文件删除的异步请求使页面无需刷新即可更新部分内容。4.4 运行与验证现在让我们启动这个文件分享服务器。启动服务器 在项目根目录 (fast_file_share) 下打开终端或命令行运行python app.py或者python3 app.py如果一切正常你将看到类似下面的输出* Serving Flask app app * Debug mode: on WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Running on all addresses (0.0.0.0) * Running on http://192.168.1.100:5000 * Running on http://192.168.31.220:5000 Press CTRLC to quit * 服务器即将启动在 http://192.168.1.100:5000 * 请在同一局域网下的设备浏览器中访问上述地址 * 上传目录: /Users/YourName/Projects/fast_file_share/uploads在本机访问 打开你的电脑浏览器访问http://127.0.0.1:5000或http://localhost:5000。你应该能看到文件分享页面。在局域网内其他设备访问找到控制台输出的非127.0.0.1的 IP 地址例如http://192.168.1.100:5000。确保你的手机或另一台电脑连接在同一个 Wi-Fi 网络下。在另一台设备的浏览器中直接输入该地址如http://192.168.1.100:5000。如果无法访问请跳到第5节排查防火墙问题。功能测试上传在页面中选择一个文件点击“开始上传”。成功后文件会出现在下方的“已共享的文件列表”中。下载在另一台设备上访问该页面点击文件对应的“下载”按钮。删除点击“删除”按钮确认后文件将从服务器移除。4.5 打包成可执行文件 (使用 PyInstaller)为了让没有 Python 环境的用户也能使用我们将程序打包成独立的.exe(Windows) 或可执行文件 (macOS/Linux)。生成依赖文件(可选但推荐) 在项目根目录执行pip freeze requirements.txt这会生成一个requirements.txt文件记录了当前环境的所有依赖。对于纯净打包我们只需要Flask和Werkzeug。安装 PyInstaller(如果尚未安装)pip install pyinstaller执行打包命令 在项目根目录下运行以下命令。关键参数解释-F: 打包成单个可执行文件。-w: 对于 GUI 程序隐藏控制台窗口。但我们这个程序需要控制台显示 IP 信息所以不加-w。--add-data: 将模板和静态资源文件夹添加到打包文件中。这是最关键的一步否则打包后的程序找不到 HTML 文件。--hidden-import: 显式告诉 PyInstaller 包含某些隐式导入的模块。Windows 命令提示符 (CMD) 或 PowerShellpyinstaller -F --add-data templates;templates --add-data uploads;uploads --hidden-importwerkzeug.utils app.pymacOS / Linux 终端pyinstaller -F --add-data templates:templates --add-data uploads:uploads --hidden-importwerkzeug.utils app.py注意--add-data参数的源路径和目标路径之间Windows 用分号;分隔macOS/Linux 用冒号:分隔。找到打包结果 打包完成后会在项目目录下生成一个dist文件夹里面就是可执行文件app.exe(Windows) 或app(macOS/Linux)。运行打包后的程序将整个dist文件夹或者只拷贝app.exe以及它依赖的templates和uploads文件夹因为 PyInstaller 的-F模式已将所有资源打包进一个文件发送给其他用户。用户双击app.exe即可启动服务器。首次运行时防火墙可能会弹出警告请选择“允许访问”。启动后控制台同样会显示访问地址。5. 常见问题与排查思路在开发和使用过程中你可能会遇到以下问题。这里提供了详细的排查步骤。问题现象可能原因解决思路运行python app.py报错ModuleNotFoundError: No module named flask未安装 Flask 或不在当前 Python 环境。1. 确认已运行pip install flask。2. 检查 VS Code 或终端是否选择了正确的 Python 解释器。局域网内其他设备无法访问http://ip:5000最常见原因防火墙阻止了端口。Windows:1. 进入“控制面板 - Windows Defender 防火墙 - 高级设置”。2. 点击“入站规则 - 新建规则”。3. 选择“端口”下一步输入5000下一步选择“允许连接”下一步全选最后命名如“Flask Server”并完成。macOS:系统偏好设置 - 安全性与隐私 - 防火墙 - 防火墙选项... - 点击“”添加你的 Python 应用或终端并设置为“允许传入连接”。上传文件时出错413 Request Entity Too Large文件大小超过 Flask 默认限制。在app.py中我们已经通过app.config[MAX_CONTENT_LENGTH]设置了 500MB 限制。如果还不够可以增大这个值单位字节。上传文件失败无错误提示1. 上传目录uploads不可写。2. 文件名包含非法字符。1. 检查uploads文件夹是否存在且有写入权限。2. 代码中已使用secure_filename处理检查其是否过滤掉了某些字符。可以打印filename变量查看。PyInstaller 打包后运行提示Jinja2 Template Not Found打包时未包含templates文件夹。确保打包命令中正确使用了--add-data参数且路径分隔符正确Windows用;macOS/Linux用:。可以检查生成的可执行文件内部结构Windows可用7-Zip打开.exe查看临时解压目录。手机访问页面样式混乱或按钮错位HTML/CSS 未做移动端适配。我们的示例 CSS 非常简单。如需更好移动端体验可以引入响应式 CSS 框架如 Bootstrap或使用media查询优化样式。服务器启动后IP 地址显示为127.0.0.1get_local_ip()函数获取 IP 失败。这通常发生在未连接局域网如仅连接了手机热点或特定网络时。函数会退回127.0.0.1。请确保电脑已连接到 Wi-Fi 或有线网络。6. 最佳实践与工程建议将这个简单的工具投入实际使用或作为项目基础时可以考虑以下优化方向使其更健壮、安全和易用。6.1 安全加固访问控制基础认证 目前任何人都能访问你的页面。可以添加简单的 HTTP 基础认证。from flask_httpauth import HTTPBasicAuth auth HTTPBasicAuth() users {“admin”: “supersecretpassword”} # 应使用哈希密码 auth.verify_password def verify_password(username, password): if username in users and users[username] password: return username app.route(‘/‘) auth.login_required def index(): # ...然后安装flask-httpauthpip install flask-httpauth。文件类型限制 示例中的ALLOWED_EXTENSIONS已经提供了基础限制。在生产环境中应严格限制可上传的文件类型防止上传可执行文件等危险内容。文件名处理 务必使用secure_filename()这是防止路径遍历攻击的关键。生产环境部署切勿在生产环境使用app.run(debugTrue)。应使用专业的 WSGI 服务器如 Gunicorn (Unix) 或 Waitress (Windows)并配合 Nginx 等反向代理。# 使用 Gunicorn 示例 pip install gunicorn gunicorn -w 4 -b 0.0.0.0:5000 app:app6.2 功能增强拖拽上传 使用 HTML5 的 File API 和 JavaScript 实现拖拽上传提升用户体验。上传进度条 对于大文件前端显示上传进度很有必要。这需要后端配合或使用 JavaScript 库如axios配合onUploadProgress事件。二维码生成 自动将服务器访问地址生成二维码手机扫码即可访问更加方便。可以使用qrcode库。import qrcode app.route(‘/qrcode‘) def generate_qrcode(): url f“http://{get_local_ip()}:5000“ img qrcode.make(url) # 将图片保存或直接返回给前端显示自定义端口与共享目录 通过命令行参数或配置文件让用户自定义端口和共享文件夹路径。import argparse parser argparse.ArgumentParser(description‘文件分享服务器‘) parser.add_argument(‘--port‘, typeint, default5000, help‘服务器端口‘) parser.add_argument(‘--folder‘, default‘uploads‘, help‘共享文件夹路径‘) args parser.parse_args() UPLOAD_FOLDER args.folder # ... 然后在 app.run 中使用 args.port日志记录 添加日志功能记录文件上传、下载、删除等操作便于审计。import logging logging.basicConfig(filename‘file_share.log‘, levellogging.INFO) app.route(‘/upload‘, methods[‘POST‘]) def upload_file(): # ... 文件保存成功后 app.logger.info(f‘User uploaded file: {filename}‘)6.3 代码组织与可维护性配置文件 将端口、上传目录、允许的扩展名、文件大小限制等配置项提取到单独的配置文件如config.py或config.ini中便于管理。蓝图与模块化 如果功能继续增加可以考虑使用 Flask 的 Blueprint 将路由分模块管理。错误处理 为关键操作如文件保存、删除添加更完善的异常捕获和用户友好的错误提示。通过这个项目你不仅实现了一个实用的工具更实践了 Python Web 开发、网络编程、前端交互和项目打包的完整流程。你可以在此基础上自由发挥添加更多有趣的功能例如 WebSocket 实现实时通知、数据库记录文件信息、甚至打造一个迷你网盘。

相关新闻