使用原生node.js搭建HTTP服务器,支持MP4视频、图片传输,支持下载rar文件
前言
如何安装node.js,如何搭建一个简易的http服务器我这里就不再赘述了,不懂的同学可以先去学习一下。当然了,我写的也就属于简易版的增强版,大家有什么高见的欢迎提出,然后进入正题。
目录结构
|-server.js
|-router.js
|-test.html
|-css|-test.css
|-js |-test.js
server.js
//原生模块
var http = require('http');
var fs = require('fs');
var url = require('url');
//自定义模块
var router = require('./router.js');
http.createServer(function(request,response){
//获取客户端访问的路径
var pathname = url.parse(request.url).pathname;
//如果用户只输入域名就改变访问路径,并发送主页的内容给客户端
if(pathname == "/"){
pathname = "/index.html";
}
//获取当前请求客户端的IP地址
var ipv4 = get_client_ipv4(request);
//输出日志到控制台
showLog(ipv4,("请求"+decodeURI(pathname)));
//判断文件是否存在
fs.exists(__dirname + decodeURI(pathname),function(exists){
if(exists){
//使用router模块的函数
router.readFileBySuffixName(pathname,fs,request,response);
}else{
console.log(decodeURI(pathname)+"文件不存在!");
//文件不存在,向客户端发送404状态码,并发送该文件不存在的字符串
response.writeHead(404,{"Content-Type":"text/plain"});
response.end(pathname+"文件不存在!");
}
});
}).listen(80); //监听80端口 console.log('web服务已运行!'); /**
* @desc 获取IPV4地址
* @param req htttp.request
* @return string 32位IP地址
*/
function get_client_ipv4(req) {
//获取任意浏览器的IP地址,
var ip = req.headers['x-forwarded-for'] ||
req.ip ||
req.connection.remoteAddress ||
req.socket.remoteAddress ||
req.connection.socket.remoteAddress || '';
//获取到的IP地址中存在IPV4和IPV6的地址,我们只需要IPV4的地址
if(ip.split(',').length>0){
ip = (ip.split(',')[0]).match(/(\d+\.\d+\.\d+\.\d+)/)[0];
}
return ip;
}; /**
* @desc 向控制台输出日志,自动在头部添加时间、地址
* @param ipv4 string
* @param message string
*/
function showLog(ipv4,message){
//获取当前时间
var date = new Date();
//转换为本地时间的字符串形式并输入到控制台
console.log(date.toLocaleDateString() + " " + date.toLocaleTimeString() +
" " + ipv4 + " " + message);
}
首先引入模块,使用http.createServer创建http服务器,并监听80端口;http.createServer的回调函数接收两个值,一个request请求对象,一个response响应对象,request对象可以获取到客户端请求的信息,response对象用来返回数据到客户端;上面创建了两个简单的工具函数,分别用来获取客户端的IPV4地址、向控制台输出日志;使用fs.exists函数判断客户端请求的文件是否存在,如果不存在则返回404状态码,如果存在,则使用下面router.js中创建的readFileBySuffixName函数,读取相应的文件并根据后缀名设置响应头,然后发送数据到客户端。
router.js
/**
* @desc 根据后缀名读取文件
* @param pathname string 文件路径 url.parse(request.url).pathname
* @param fs fs
* @param request htttp.request
* @param response https.response
*/
exports.readFileBySuffixName = function(pathname,fs,request,response){
var ext = pathname.match(/(\.[^.]+|)$/)[0];//取得后缀名
switch(ext){ //根据后缀名读取相应的文件,设置响应头,并发送到客户端
case ".css":
case ".js":
//读取文件
fs.readFile("."+request.url,'utf-8',function(err,data){
if(err) throw err;
response.writeHead(200,{ //根据不同的后缀设置不同的响应头
"Content-Type":{
".css":"text/css",
".js":"application/javascript",
}[ext]
});
response.write(data); //发送文件数据到客户端
response.end(); //发送完成
});
break;
//jpg、gif、png后缀的图片
case ".jpg":
case ".gif":
case ".png":
//二进制读取文件
fs.readFile("."+decodeURI(request.url),'binary',function(err,data){
if(err)throw err;
response.writeHead(200,{
"Content-Type":{
".jpg":"image/jpeg",
".gif":"image/gif",
".png":"image/png",
}[ext]
});
response.write(data,'binary'); //发送二进制数据
response.end();
});
break;
case ".mp4":
//读取文件的状态
fs.stat('.'+decodeURI(request.url),function(err,stats){
if(err){
if(err.code === 'ENOENT'){
return response.sendStatus(404);
}
response.end(err);
}
//断点续传,获取分段的位置
var range = request.headers.range;
if(!range){
//206状态码表示客户端通过发送范围请求头Range抓取到了资源的部分数据
//416状态码表示所请求的范围无法满足
return response.sendStatus(416);
}
//替换、切分,请求范围格式为:Content-Range: bytes 0-2000/4932
var positions = range.replace(/bytes=/,"").split("-");
//获取客户端请求文件的开始位置
var start = parseInt(positions[0]);
//获得文件大小
var total = stats.size;
//获取客户端请求文件的结束位置
var end = positions[1] ? parseInt(positions[1],10):total -1;
//获取需要读取的文件大小
var chunksize = (end-start) + 1; response.writeHead(206,{
"Content-Range":"bytes "+ start+"-"+end+"/"+total,
"Accept-Ranges":"bytes",
"Content-Length":chunksize,
"Content-Type":"video/mp4"
});
//创建读取流
var stream = fs.createReadStream('.'+decodeURI(request.url),{start:start,end:end})
.on("open",function(){
stream.pipe(response); //读取流向写入流传递数据
}).on("error",function(err){
response.end(err);
});
});
break;
case ".rar":
//同步读取文件状态
var stats = fs.statSync("." + decodeURI(request.url));
response.writeHead(200,{
"Content-Type": "application/octet-stream", //相应该文件应该下载
//模板字符串
"Content-Disposition": `attachment; filename = ${pathname.replace("/","")}`,
"Content-Length":stats.size
});
//管道流
fs.createReadStream("." + decodeURI(request.url)).pipe(response);
break;
//以上都不匹配则使用默认的方法
default:
fs.readFile('.'+pathname,'utf-8',function(err,data){
response.writeHead(200,{
"Content-Type":"text/html"
});
response.write(data);
response.end();
});
}
}
router.js文件中只有一个readFileBySuffixName函数,该函数的作用是判断客户端访问文件的后缀名,css、js、图片、mp4视频、rar文件等都能成功返回到客户端;其中视频和下载文件使用流传输;因为如果不使用流的话,服务器要先缓存文件,然后再发送文件到客户端;使用HTML5视频的客户端会发送一个Content-Range的值到服务器,服务器根据这个range值读取一个文件指定的部分,并返回这个特定的部分数据到客户端,就实现了视频的断点续传,你可以随意的跳转到视频的任意一部分了!
进入项目文件夹,输入
node ./server.js
服务器端输出日志和测试页面


favicon.ico文件是该页面的图标文件,第一次进入页面浏览器会自动请求。
使用原生node.js搭建HTTP服务器,支持MP4视频、图片传输,支持下载rar文件的更多相关文章
- 使用 Node.js 搭建 Web 服务器
使用Node.js搭建Web服务器是学习Node.js比较全面的入门教程,因为实现Web服务器需要用到几个比较重要的模块:http模块.文件系统.url解析模块.路径解析模块.以及301重定向技术等, ...
- 学习 node.js 搭建web服务器
开始 学习使用 node.js 首先完成搭建一个 web服务器.myweb.js var http = require('http'); var url = require('url'); var h ...
- 用node.js搭建本地服务器
我的第一篇笔记来写写node.js,我对node.js的并不是很了解,基本的项目路径变换还是会的.原先我下载node.js就是我想学vue.js,后来因为工作的繁忙搁浅了我的计划.最近在学习phase ...
- node.js搭建Web服务器
Node.js 博客搭建 一. 学习需求 Node 的安装运行 会安装node,搭建node环境 会运行node. 基础模块的使用 Buffer:二进制数据处理模块 Event:事件模块 fs:文件系 ...
- node.js搭建https服务器
HTTPS简介 HTTPS:(全称:Hypertext Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版. ...
- Node.js学习笔记(五) --- 使用Node.js搭建Web服务器
1. Node.js 创建的第一个应用 1.引入http模块 var http = require("http"); 2. 创建服务器接下来我们使用 http.createServ ...
- express+node.js搭建的服务器和在sublimeServer下的页面请求报跨域错误
1.前端页面使用vue中的axios请求nodejs响应.报以下错误: Failed to load http://localhost:3000/users/validate: Response to ...
- 使用node.js搭建本地服务器
第一步安装node:https://nodejs.org/zh-cn/download/ 接下来就需要安装http的镜像文件 打开cmd:输入以下命令 npm install http-server ...
- 如何使用Node.js搭建一个服务器
在node环境中运行下面的代码 "use strict"; const http = require("http"), path = require(" ...
随机推荐
- docker 管理应用程序数据和网络管理
Volume和Bind Mount Docker提供三种不同方式将数据从宿主机挂载到容器中:volumes,bind mounts和tmpfs volumes:Docker管理宿主机文件系统的一部分( ...
- [Java复习] 多线程 Multithreading
Q1多线程基础 进程和线程? 进程: 1. 一段程序执行过程,动态的,相对而言程序是静态的.(与类和对象的关系类似) 2. CPU资源分配最小单元,包括CPU调度和资源管理. 3. 一个进程可以有多个 ...
- coursera 视频总是缓冲或者无法观看的解决办法(Windows 和 Linux 系统 环境)
现在读了一个机器学习方向的博士,虽然这么长时间也没有学明白什么,但是没事的时候也会看看一些书籍和资料,学这个方向的人基本都会看过吴恩达的coursera课程上的机器学习课程,我也是如此,不过交了钱以后 ...
- 小D课堂 - 新版本微服务springcloud+Docker教程_6-03 高级篇幅之zuul常用问题分析
笔记 3.高级篇幅之Zuul常用问题分析和网关过滤器原理分析 简介:讲解Zuul网关原理和过滤器生命周期, 1.路由名称定义问题 路由映射重复覆盖问题 ...
- Java日志体系(三)commons-logging
1.1 简介 Apache Commons Logging,又名JakartaCommons Logging (JCL),它是Apache提供的一个通用的日志接口,它的出现避免了和具体的日志方案直接耦 ...
- Spring Cloud(0):目录
Spring Cloud(1):概览 Spring Cloud(2):服务发现(Eureka) Spring Cloud(3):配置服务(Config) Spring Cloud(4):断路器(Hys ...
- wdScrollTab
wdScrollTab是一个采用jQuery实现的Tab面板,当标签太多超出页面时会自动滚动.支持iframe.ajax调用和动态加载内容.
- ubantu使用小结
一.root账户问题 1.初始登录的时候root密码是随机的,自己改一个. 2.登录界面没有root选项 解决: #gedit /usr/share/lightdm/lightdm.conf.d/50 ...
- 无监督异常检测之LSTM组成的AE
我本来就是处理时间序列异常检测的,之前用了全连接层以及CNN层组成的AE去拟合原始时间序列,发现效果不佳.当利用LSTM组成AE去拟合时间序列时发现,拟合的效果很好.但是,利用重构误差去做异常检测这条 ...
- Spring+SpringMvc+Hibernate整合记录
Spring+SpringMvc+Hibernate+Maven整合各大配置文件记录 1.Idea新建的Maven架构 2.Maven的对象模型的内容 <project xmlns=" ...