<javascript><css><nodejs>使用express构建一个本地服务器,使用http获取服务器图片和视频,网页端grid布局显示

news/2024/12/21 19:45:00/

前言
本文是一个前端示例,是基于nodejs使用express构建一个简单的服务器,并扫描本地资源文件夹,获取视频和图片,网页端通过http来向服务器请求,并将返回的资源在网页端程序,布局为grid。

环境配置
系统:windows
平台:visual studio code
语言:javascript、html、css
库:nodejs

概述
本文是一个前端学习的示例,主要的内容是构建一个服务端,网页端通过路由来访问服务端资源。

代码实现
我们首先创建一个项目文件夹,并在文件夹下新建一个js文件,名为server.js,用于编写服务端代码。
本例中我们使用express来构建服务器:

javascript">const express = require('express');
const fs = require('fs');
const path = require('path');const app = express();
const PORT = 3000;
const videoFolder = path.join(__dirname, 'videos');
const thumbnailFolder = path.join(__dirname, 'thumbnails'); // 假设有预生成的封面图片
console.log(thumbnailFolder);
const supportedExtensions = ['.mp4', '.avi', '.mov', '.mkv']; // 支持的视频格式
const defaultThumbnail='./thumbnails/default.png';//构建静态文件目录
app.use(express.static(path.join(__dirname,'public')));
app.use('/videos',express.static(path.join(__dirname,'videos')));function getfiletype(filePath){const ext=path.extname(filePath).toLowerCase();const typeMap={'.mp4':'video','.avi':'video','.mov':'video','.mkv':'video','.png':'image','.jpg':'image','.txt':'text','.json':'json'};return typeMap[ext] || 'unknown';
}/***扫描资源文件夹* @param {*} folderPath * @param {*} files * @returns */
function getallfile(folderPath,files=[]){const items=fs.readdirSync(folderPath);const result=[];items.forEach(item=>{const itemPath=path.join(folderPath,item);const stat=fs.statSync(itemPath);if(stat.isDirectory()){const subresult={videos:[],images:[],texts:[],jsons:[]};const subitmes=fs.readdirSync(itemPath);subitmes.forEach(subitem=>{const subitempath=path.join(itemPath,subitem);//console.log(subitempath);const subitem2=path.join('videos',item,subitem);//console.log(item);//console.log(subitem2);const substat=fs.statSync(subitempath);if (substat.isFile()){const filetype=getfiletype(subitempath);if (filetype === 'video'){subresult.videos.push(subitem2);//generatethmbnail(item,subitem,'00:00:02.000');} else if (filetype === 'image'){subresult.images.push(subitem2);}   else if( filetype === 'text'){subresult.texts.push(subitem2);} else if( filetype === 'json'){subresult.jsons.push(subitem2);}}});result.push(subresult);}});return result;}app.get('/api/videos', (req, res) => {const allfiles=getallfile(videoFolder);//console.log(allfiles);res.json(allfiles);
});
app.get('/play', (req, res) => {loadfile('./public/play.html',res);})app.get('/video',(req,res)=>{const videoname=req.query.name;const videoPath = path.join(__dirname, videoname);//console.log(videoPath);const stat = fs.statSync(videoPath);const fileSize = stat.size;const range = req.headers.range;if (range) {const parts = range.replace(/bytes=/, "").split("-");const start = parseInt(parts[0], 10);const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;const chunkSize = (end - start) + 1;const file = fs.createReadStream(videoPath, { start, end });const head = {'Content-Range': `bytes ${start}-${end}/${fileSize}`,'Accept-Ranges': 'bytes','Content-Length': chunkSize,'Content-Type': 'video',};res.writeHead(206, head);file.pipe(res);} else {const head = {'Content-Length': fileSize,'Content-Type': 'video/mp4',};res.writeHead(200, head);fs.createReadStream(videoPath).pipe(res);}
})
/*** 读取html文件内容* @param {*} filePath */
function loadfile(filePath,res){// 解析文件扩展名const extname = path.extname(filePath);let contentType = 'text/html';switch (extname) {case '.css':contentType = 'text/css';break;case '.js':contentType = 'text/javascript';break;case '.json':contentType = 'application/json';break;case '.png':contentType = 'image/png';break;case '.jpg':contentType = 'image/jpg';break;// 可以根据需要添加更多的MIME类型}// 读取文件内容fs.readFile(filePath, (error, content) => {if (error) {if (error.code == 'ENOENT') {// 文件未找到,返回404res.writeHead(404, { 'Content-Type': contentType });res.end('File not found', 'utf-8');} else {// 服务器错误,返回500res.writeHead(500);res.end('Sorry, check with the site admin for error: ' + error.code + ' ..\n', 'utf-8');}} else {// 文件读取成功,返回文件内容res.writeHead(200, { 'Content-Type': contentType });res.end(content, 'utf-8');};});};app.listen(PORT,'localhost', () => {console.log(`Server is running on port http://localhost:${PORT}`);
});

然后在项目文件夹下,创建public文件夹,配置为静态文件目录,在public文件夹下,新建一个index.html文件:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Video Folder Scanner</title><link rel="stylesheet" href="styles.css"><style>css">.thumbnail {width: 150px;height: 100px;object-fit: cover;cursor: pointer;margin: 10px;}</style>
</head>
<body><h1>Video Folder</h1><div id="thumbnails" class="thumbnails-container"></div><script src="./index.js"></script>
</body>
</html>

再创建一个styles.css文件和一个index.js文件。
index.js

javascript">document.addEventListener('DOMContentLoaded', () => {const urls=[];async function getallurl(){const response=await fetch('http://localhost:3000/api/videos');const data=await response.json();return data;}  async function gettext(){const fileinfos=await getallurl();console.log(fileinfos);for(const fileinfo of fileinfos){console.log(fileinfo);const videourl=fileinfo.videos[0];const imgurl=fileinfo.images[0];const jsonurl=fileinfo.jsons[0];const response = await fetch(`http://localhost:3000/${jsonurl}`);if (!response.ok) {throw new Error('Network response was not ok');}const data = await response.json();const thumbnails=document.getElementById('thumbnails');const div1=document.createElement('div');div1.className='div1';const infodiv=document.createElement('div');infodiv.className='infodiv';const imgdiv=document.createElement('div');imgdiv.className='imgdiv';const img=document.createElement('img');const videoname=data['name'];const p1=document.createElement('p');p1.textContent=`${videoname}`;img.className='img';img.src=imgurl;img.addEventListener('click',()=>{//window.location.href= `${video.videoUrl}`;window.location.href=`./play?path=${videourl}&data=${jsonurl}`;});imgdiv.appendChild(img);imgdiv.appendChild(p1);thumbnails.appendChild(imgdiv);console.log(data);}};gettext();});

styles.css

css">.thumbnails-container{display: grid;grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* 自动填充列,最小宽度200px */gap: 20px; /* 网格项之间的间距 */
}.imgdiv{margin: 10px;padding: 10px;border: 1px solid #ddd;border-radius: 8px;box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);transition: transform 0.2s;overflow: hidden;
}
.imgdiv:hover{background-color: #a5dff7;transform: scale(1.05);
}
.img{width: 100%;height: auto;display: block;border-radius: 8px;
}/* 针对不同屏幕尺寸调整布局 */
@media (max-width: 1200px) {.imgdiv {width: calc(33.333% - 40px); /* 3列布局,减去间距 */}
}@media (max-width: 800px) {.imgdiv {width: calc(50% - 40px); /* 2列布局,减去间距 */}
}@media (max-width: 500px) {.imgdiv {width: calc(80% - 40px); /* 单列布局,减去间距 */}
}

当我们启动服务器后,并访问http://localhost:3000/,网页端显示如下(仅供参考):
在这里插入图片描述
此处,图片与显示名称,依旧实际文件夹内的内容来,以上是我测试时使用的资源文件夹内的图片等内容。
图片相当于是封面图,点击图片后,会跳转到另一个页面:
在这里插入图片描述
此处,要播放的视频,是在服务器的路由中已经配置的,服务器端会根据请求的视频名称,采用流式媒体播放视频。

注:本文是一个记录,用于以后参考,如果刚好对你也有帮助,那么也是不错的。


http://www.ppmy.cn/news/1557000.html

相关文章

跨越平台界限:探索Native AOT的交叉编译技术

在当今多元化的技术生态中&#xff0c;软件开发者们经常面临一个挑战&#xff1a;如何使应用程序能够在不同的操作系统和硬件平台上无缝运行。传统的解决方案通常依赖于解释型语言或虚拟机技术&#xff0c;但这些方法在某些高性能要求或资源受限的场景中可能并不理想。Native A…

python读excel数据

python读取excel时默认第一行是标题&#xff0c;因此推荐采用matlab先加全零行再读数 示例&#xff1a; 首先用matlab生成excel文件&#xff0c;记为data_mat.xlsx clc clear close all dataones(5,5); xlswrite(data_mat.xlsx,data)再用matlab加零行 clc clear close all %%…

Vue.js前端框架教程12:Vue表单验证rules和form.validate

文章目录 表单验证:rulesformRef.value.validate 表单验证 在 Vue 中&#xff0c;:rules 和 formRef.value.validate 通常用于表单验证。:rules 是一个对象&#xff0c;定义了表单字段的验证规则&#xff0c;而 formRef.value.validate 是一个方法&#xff0c;用于触发表单验证…

Oracle 数据库中,UNION ALL创建视图的使用详解

目录 UNION ALL 的特点 UNION ALL 的作用 1. 合并结果集 2. 保留重复行 3. 提高性能 UNION ALL 的使用场景 1. 日志或数据拼接 2. 区分数据来源 3. 解决分区表查询 注意事项 在创建视图中的作用 场景 1&#xff1a;合并多个表的数据到视图 表结构 目标 SQL 实现…

7 家使用量子计算的公司

劳斯莱斯、Deloitte、BASF、Roche、富士通、JPMorgan和宝马是率先开展量子计算实验的部分公司。 商用量子计算的实现仍需数年时间&#xff0c;但这并未阻止世界上一些知名企业对其进行试验。在许多情况下&#xff0c;利用当下有噪声的中等规模量子&#xff08;NISQ&#xff09…

ACL-2024 | MapGPT:基于地图引导提示和自适应路径规划机制的视觉语言导航

作者&#xff1a; Jiaqi Chen, Bingqian Lin, Ran Xu, Zhenhua Chai, Xiaodan Liang, Kwan-Yee K. Wong, 单位&#xff1a; 香港大学&#xff0c;中山大学深圳校区&#xff0c;美团 原文链接&#xff1a;MapGPT: Map-Guided Prompting with Adaptive Path Planning for Visio…

跨站脚本攻击(XSS)可能存在的位置与实操演示

免责申明 本文仅是用于学习研究XSS攻击的原理,请勿用在非法途径上,若将其用于非法目的,所造成的一切后果由您自行承担,产生的一切风险和后果与笔者无关;本文开始前请认真详细学习《‌中华人民共和国网络安全法》【学法时习之丨网络安全在身边一图了解网络安全法_中央网络安…

量子通信学习路径(一)

量子通信是一门融合量子力学和通信技术的交叉学科&#xff0c;其核心目标是利用量子力学的特性&#xff08;如叠加态和纠缠&#xff09;实现信息传递和安全通信。以下是一个系统学习量子通信的完整大纲&#xff0c;从基础知识到实际应用逐步深入&#xff0c;帮助建立全面的知识…