当前位置: 首页 > ops >正文

whttpserver:一个命令极速搭建文件上传与下载服务器

whttpserver 是一个简单的HTTP服务器,类似于python -m http.server,但增加了文件上传和编辑的功能。

1. 安装 whttpserver 模块
# 临时设置环境变量 PYTHONUTF8=1,强制 Python 使用 UTF-8 编码
set PYTHONUTF8=1
pip install whttpserver
2. 启动服务
whttpserver --port <服务器监听的端口号,默认为25000> --dir <"文件上传和下载的根目录"> --debug <True or False>

启动信息如下:

在浏览器地址栏中,输入 http://127.0.0.1:8181/

3. 定制模板

可以看到,默认的页面比较简陋,我们可以修改下模板文件,让它看起来更美观一些。

模板文件路径为:%python安装目录%/Lib/site-packages/whttpserver/templates/index.html

修改后的 index.html 文件内容如下:

<!DOCTYPE html>
<html lang="zh">
<head><title>Directory listing for {{the_path}}</title><style>* {margin: 0;padding: 0;box-sizing: border-box;}body {font-family: "Microsoft YaHei", "微软雅黑", Arial, sans-serif;background: linear-gradient(135deg, #f5f7fa 0%, #e4edf5 100%);color: #2c3e50;min-height: 100vh;padding: 20px;overflow: hidden; /* 确保整个页面无滚动条 */display: flex;flex-direction: column;}.header {display: flex;justify-content: space-between;align-items: center;margin-bottom: 25px;padding-bottom: 15px;border-bottom: 1px solid rgba(44, 62, 80, 0.1);}.breadcrumb {display: flex;align-items: center;gap: 8px;font-size: 18px;}.breadcrumb a {color: #3498db;text-decoration: none;transition: all 0.3s ease;padding: 5px 10px;border-radius: 4px;}.breadcrumb a:hover {background: rgba(52, 152, 219, 0.1);transform: translateY(-2px);}.breadcrumb span {color: #7f8c8d;}.upload-section {background: white;border-radius: 12px;padding: 20px;box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);margin-bottom: 25px;}.upload-form {display: flex;gap: 15px;align-items: center;}.file-input {flex: 1;padding: 12px 15px;border: 2px dashed #3498db;border-radius: 8px;background: rgba(52, 152, 219, 0.05);font-size: 16px;cursor: pointer;}.refresh-btn {background: #009688;color: white;border: none;padding: 12px 25px;border-radius: 8px;font-weight: 600;cursor: pointer;transition: all 0.3s ease;box-shadow: 0 4px 10px rgba(52, 152, 219, 0.3);}.upload-btn {background: #3498db;color: white;border: none;padding: 12px 25px;border-radius: 8px;font-weight: 600;cursor: pointer;transition: all 0.3s ease;box-shadow: 0 4px 10px rgba(52, 152, 219, 0.3);}.upload-btn:hover {background: #2980b9;transform: translateY(-2px);box-shadow: 0 6px 15px rgba(52, 152, 219, 0.4);}.messages {margin-top: 15px;padding: 10px;border-radius: 6px;background: rgba(46, 204, 113, 0.1);color: #27ae60;display: none;}.uploading-message {margin-top: 10px;color: #3498db;font-style: italic;}.table-container {background: white;border-radius: 12px;overflow: hidden;box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);flex: 1;display: flex;flex-direction: column;max-height: calc(100vh - 300px); /* 确保表格高度适应屏幕 */}.table-header {padding: 20px;border-bottom: 1px solid rgba(44, 62, 80, 0.1);}.table-header h3 {font-size: 22px;color: #2c3e50;}.table-scroll {overflow-y: auto;max-height: calc(100vh - 320px); /* 确保表格内容不超出视口 */}/* 隐藏滚动条但保留功能 */.table-scroll::-webkit-scrollbar {width: 0;height: 0;}table {width: 100%;border-collapse: separate;border-spacing: 0;font-size: 15px;}th {background: #f8f9fa;color: #7f8c8d;font-weight: 600;text-align: left;padding: 15px 20px;position: sticky;top: 0;border-bottom: 2px solid #ecf0f1;}td {padding: 12px 20px;border-bottom: 1px solid #ecf0f1;}tr:hover td {background: rgba(236, 240, 241, 0.5);}.file a {color: #27ae60;text-decoration: none;font-weight: 500;transition: all 0.2s ease;}.dir a {color: #3498db;text-decoration: none;font-weight: 500;transition: all 0.2s ease;}.file a:hover, .dir a:hover {text-decoration: underline;opacity: 0.9;}.footer {text-align: center;padding: 20px;color: #7f8c8d;font-size: 14px;margin-top: 20px;border-top: 1px solid rgba(44, 62, 80, 0.1);}</style>
</head>
<body><div class="header"><div class="breadcrumb"><a href="/">根目录</a><span>›</span><a href="{{ parent_path }}">上一级</a></div><h3><input type="button" value="刷 新" class="refresh-btn" onclick="javascript: location.href = location.href;"></h3><h3>文件目录管理器</h3></div><div class="upload-section"><form class="upload-form" method="post" action="/upload?path={{req_path}}" enctype="multipart/form-data" target="hidden_iframe" onsubmit="return addMessage();"><input type="file" name="file" class="file-input"><input type="submit" value="上传文件" class="upload-btn" onclick="showUploadingMessage();"></form><div id="messages" class="messages"></div><div id="uploadingMessage" class="uploading-message" style="display:none;">正在上传文件,请稍候...</div></div><div class="table-container"><div class="table-header"><h4>当前目录: {{the_path}}</h4></div><div class="table-scroll"><table><thead><tr><th>文件名称</th><th>文件类别</th><th>文件大小</th><th>访问权限</th><th>所属用户</th><th>所属组</th>                <th>最后修改时间</th></tr></thead><tbody>{% for item in data %}<tr class="{{ item.type }}"><td><a href="{{ item.href }}" class="{{ item.type }}">{{ item.name }}</a></td><td>{{ item.type }}</td><td>{{ item.size }}</td><td>{{ item.permissions }}</td><td>{{ item.owner }}</td><td>{{ item.group }}</td><td>{{ item.mtime }}</td></tr>{% endfor %}</tbody></table></div></div><div class="footer"><p>文件目录管理系统 | 优雅简洁的文件浏览体验</p></div><iframe name="hidden_iframe" id="hidden_iframe" style="display:none;"></iframe><script type="text/javascript">function showUploadingMessage() {document.getElementById('uploadingMessage').style.display = 'block';}function addMessage() {var iframe = document.getElementById('hidden_iframe');iframe.onload = function() {var content = iframe.contentDocument || iframe.contentWindow.document;var message = content.body.innerHTML;var messagesDiv = document.getElementById('messages');messagesDiv.innerHTML = '<p>' + message + '</p>';messagesDiv.style.display = 'block';document.getElementById('uploadingMessage').style.display = 'none';// 3秒后隐藏消息setTimeout(function() {messagesDiv.style.display = 'none';location.href = location.href;}, 3000);};return true;}</script>
</body>
</html>

新模板的页面效果如下:

 

🏷️ 如有疑问,可以关注 我的知识库,直接提问即可。 

http://www.xdnf.cn/news/13288.html

相关文章:

  • 前端开发中vue的脚手架你知道是什么意思吗?
  • Kafka 2.7.0 单节点安装与启动教程(适配 JDK 1.8)
  • C++ 中的函数重载
  • 【S905X3通刷】【HK1 BOX】【适配slimBOXtv所有机型】slimBOXtv-9.17.2-ATV系统中文版线刷固件包
  • 循环冗余码校验CRC码 算法步骤+详细实例计算
  • ​​扩散模型调度器(Scheduler)
  • Linux系统编程-DAY12
  • 【第二十一章 SDIO接口(SDIO)】
  • Springboot度假村住宿服务平台95i1e(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
  • BUUCTF杂项MISC题解题思路(2)(不断更新)
  • Day50打卡 @浙大疏锦行
  • CppCon 2015 学习:Implementing class properties effectively
  • 维度建模是什么意思?如何实现维度建模?
  • Postgresql数据库初体验
  • 全连接网络
  • java常量池和字符串常量池
  • 24-Oracle 23 ai ​Lock-Free Reservations​(无锁列值保留)
  • Vue3通过自定义指令实现数字滚动动画效果
  • 《Playwright:微软的自动化测试工具详解》
  • 联邦学习聚合参数操作详解
  • 关于个性化头像框设计的分享与服务说明
  • cv::Range的用法
  • AI时代的“数据之困”,什么是AI-Ready Data
  • 介绍一种直流过压保护电路
  • 蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
  • AUTOSAR图解==>AUTOSAR_TR_SWCModelingGuide
  • 【Java工程师面试全攻略】Day7:分布式系统设计面试精要
  • C++ 类继承
  • 《驭码CodeRider 2.0深度体验:AI驱动研发全流程革新,开发效率飙升300%!》
  • 实现建筑互联互通目标,楼宇自控系统在设备管理中作用凸显