操作fs模块

const path = require("path");
const fs = require("fs"); /*
相对路径是命令窗口执行的目录
node 提供了path模块来操作路径相关的api, 其中__dirname是一个内置的变量,返回当前文件所在的目录
*/
const getDirUrl = dir => {
return path.resolve(__dirname, dir);
};
for (let i = 0; i < 5; i++) {
fs.writeFileSync(getDirUrl("./create01.text"), i + "、我是测试数据" + i + "\n", {
flag: "a+",
encoding: "utf-8"
});
} console.log("hello nodejs"); const data = fs.readFileSync(getDirUrl("./create01.text"), {encoding: 'utf-8'}).toString()
console.log('同步读取')
console.log(data) console.log('异步读取')
fs.readFile(getDirUrl("./create01.text"), (err, data) => {
if(!err) {
console.log(data.toString());
} else {
console.error(err);
}
});

在窗口执行对应的目录即可,我这里是:

操作http模块

// 1. 导入http模块
const http = require("http");
const fs = require("fs");
const path = require("path"); const mimes = {
html: "text/html",
css: "text/css",
js: "text/javascript",
png: "image/png",
jpg: "image/jpeg",
gif: "image/gif",
mp4: "video/mp4",
mp3: "audio/mpeg",
json: "application/json"
};
//2. 创建服务对象 create 创建 server 服务
// request 意为请求. 是对请求报文的封装对象, 通过 request 对象可以获得请求报文的数据
// response 意为响应. 是对响应报文的封装对象, 通过 response 对象可以设置响应报文
const server = http.createServer((req, res) => {
let { url, method } = req;
// 文件夹路径
const rootDir = __dirname + "/public"; let filePath = rootDir + url;
if (!fs.existsSync(filePath)) {
return
}
// 读取内容
fs.readFile(filePath, (err, data) => {
if (err) {
console.log(err);
//设置字符集
res.setHeader('content-type','text/html;charset=utf-8');
//判断错误的代号
switch(err.code){
case 'ENOENT':
res.statusCode = 404;
res.end('<h1>404 Not Found</h1>');
case 'EPERM':
res.statusCode = 403;
res.end('<h1>403 Forbidden</h1>');
default:
res.statusCode = 500;
res.end('<h1>500 Internal Server Error</h1>');
}
return;
}
//获取文件的后缀名
let ext = path.extname(filePath).slice(1);
//获取对应的类型
let type = mimes[ext];
if(type){
if(ext === 'html'){
res.setHeader('content-type', type + ';charset=utf-8');
}else{
res.setHeader('content-type', type);
}
}else{
//没有匹配到-默认设置二进制文件类型
res.setHeader('content-type', 'application/octet-stream');
}
//响应文件内容
res.end(data);
});
}); //3. 监听端口, 启动服务
server.listen(9000, () => {
console.log("服务已经启动,9000端口监听中...");
});

如上最简单的http 服务起来了,在浏览器中 输入 http://localhost:9000/index.html 得到如下页面

通过匹配后缀,在public文件中返回对应的资源,代码结构如下

都是一些很简单的代码就不贴了,如果需要留下邮箱即可。

其他模块看看官网的文档即可,不在记录。

框架

上面都是通过原始的方式来使用node,其实node的生态也很丰富,有很多的框架让我们选择,如 express、koa2、nestjs、midwayjs 等等

express 基本使用

// 1.0 导入express
const express = require('express')
// 2.0 express 实例
const app = express()
const port = 9000 // 3.0 路由
app.get('/', (req, res) => {
res.send('基本使用 Hello World!')
}) // 启动服务
app.listen(port, () => {
console.log(`启动服务,端口: ${port}`)
})

通常我们使用脚手架,这样可以得到统一的项目结构 如 express_ generator,具体查看express 官网

中间件-洋葱模型

  目前比较流行的 nodejs http 服务框架使用拦截器模式,这种模式将 http 请求响应的过程分为若干切面,每个切面上进行一项或若干项关联的操作。比如说,我们可以通过不同的拦截切面处理用户信息验证、会话(session)验证、表单数据验证、query 解析,或者业务逻辑处理等等。这种架构设计让切面与切面之间彼此独立。

有点面向切面编程的概念,不知道对不对。

手动实现一个拦截器:实现类似如下效果

async (ctx, next) => {
do sth...
}

通过调用next 执行下一个函数,可以中途return退出,也可以继续调用next直到最后一个函数,然后在一层一层的返回,洋葱的结构跟这个类似,所以叫洋葱模型。

这里的中间件其实是一个函数,在外层使用use 注入进来。

执行第一个中间件的fn,调用next 进入到下一个中间件,继续执行下一个fn,调用next 友进入下一个中间件,继续重复上述逻辑,直至最后一个中间件,直至最后一个中间件,就会执行 next 语句后面的代码,然后继续上一个中间件的next后置语句,继续重复上述逻辑,直至执行第一个中间件的next后置语句,最后输出,这个执行的机制,称为洋葱模型
 

模拟洋葱模型

 洋葱模型关键在于怎么处理next 参数,next是下一个函数的引用, ,可以通过我们索引加闭包,或者累加器的形式来处理,为了方便直接使用累加器的形式即可,如下代码:

/*
这个思路通过利用累加器函数的特性,返回一个函数
*/
class Interceptor {
aspects = [];
use (fn) {
this.aspects.push(fn)
return this
}
async run (context) {
// 从右往左开始遍历
const proc = this.aspects.reduceRight(
function (a, b) {
let flag = false
return async () => {
// a 上一个fn,也就是调用的时传入的 next
if (flag) {
return
}
flag = true
await b(context, a)
}
},() => Promise.resolve())
try {
// 通过这个reduceRight 让函数串起来了
await proc()
} catch (e) {
console.error(e);
}
}
} // 测试
const inter = new Interceptor()
inter.use(function a(context, next) {
console.log("a");
next();
console.log("a_after");
});
inter.use(function b(context, next) {
console.log("b");
next();
console.log("b_after");
});
inter.use(function c(context, next) {
console.log("c");
next();
console.log("c_after");
});
inter.use(function d(context, next) {
console.log("d");
next();
console.log("d_after");
});
inter.run();

输出a、b、c、d、d_after、c_after、b_after、a_after 其中koa2 源码中使用了索引加闭包的形式来处理 源码

小结

  理解了nodejs 写起来还是挺顺手的,官网文档也还好。至于其他如sql路由保持会话状态等后台基本知识点,看看相关文档即可,并没有什么难度。

  nodejs 入门基本也结束了。

nodejs 入门基本操作的更多相关文章

  1. nodeJs 5.0.0 安装配置与nodeJs入门例子学习

    新手学习笔记,高手请自动略过 安装可以先看这篇:http://blog.csdn.net/bushizhuanjia/article/details/7915017 1.首先到官网去下载exe,或者m ...

  2. NodeJS入门(四)—— path对象

    很快Node就会迎来4.0的时代,届时将并入现有的iojs,所以先前写过的iojs入门系列直接更名为NodeJS入门. 本篇开始将逐个介绍Node的各主要模块,依循API文档走一遍,但会给出比API文 ...

  3. 01.Nodejs入门之Helloworld

    说明:本文章可供有一定js基础的朋友参考nodejs入门,本文未讲解nodejs的安装,如有需要的同学可以加QQ3382260752找我,进行交流学习. 1.新建文件夹helloworld demo, ...

  4. NodeJS入门简介

    NodeJS入门简介 二.模块 在Node.js中,以模块为单位划分所有功能,并且提供了一个完整的模块加载机制,这时的我们可以将应用程序划分为各个不同的部分. const http = require ...

  5. python selenium webdriver入门基本操作

    python selenium webdriver入门基本操作 未经作者允许,禁止转载! from selenium import webdriver import time driver=webdr ...

  6. Docker 入门(Mac环境)-part 1 入门基本操作

    part-1 入门基本操作 Docker 安装 去官网下载对应的版本,然后点击安装就可以了: 如果环境是Linux,可以参照之前写的get started教程 查看docker版本 docker -- ...

  7. nodejs入门教程之http的get和request简介及应用

    nodejs入门教程之http的get和request简介及应用 前言 上一篇文章,我介绍了nodejs的几个常用的模块及简单的案例,今天我们再来重点看一下nodejs的http模块,关于http模块 ...

  8. 57.NodeJS入门--环境搭建 IntelliJ IDEA

    转自:https://blog.csdn.net/wang19891106/article/details/51127133 NodeJS入门–环境搭建 IntelliJ IDEA 本人也刚开始学习N ...

  9. 二、NodeJS入门——准备工作(2)——MongoDB安装以及客户端Robomongo安装和使用

    目录     1.介绍     2.下载地址     3.MongoDB安装过程     4.MongoDB的使用     5.MongoDB添加管理员账户     6.RoboMongo安装过程   ...

  10. NodeJS入门--环境搭建 IntelliJ IDEA

    NodeJS入门–环境搭建 IntelliJ IDEA 本人也刚开始学习NodeJS,所以以此做个笔记,欢迎大家提出意见. 1.首先 下载安装NodeJS,下载安装IntelliJ IDEA 2.接下 ...

随机推荐

  1. 在golang中如何正确判断接口是否为nil

    本文主要来分析一下在golang中,如何判断interface是否为nil,以及相关注意事项. 正常情况下,我们声明一个interface类型的变量,默认值将会返回nil,以golang自带的io.W ...

  2. nat是干什么的,为什么要有nat?以及谈谈ovs里使用ct实现nat功能

    博客竟然不显示更新的时间,只有个发布时间.看起来像2个月没更新一样,其实更新了几行呢.好几个东西想理一下,本来想和周记放一起了,但放一起就没有主题了. 当然一搜也有一些很好的博客,更详细:https: ...

  3. 存算分离实践:JuiceFS 在中国电信日均 PB 级数据场景的应用

    01- 大数据运营的挑战 & 升级思考 大数据运营面临的挑战 中国电信大数据集群每日数据量庞大,单个业务单日量级可达到 PB 级别,且存在大量过期数据(冷数据).冗余数据,存储压力大:每个省公 ...

  4. 「学习笔记」平衡树基础:Splay 和 Treap

    「学习笔记」平衡树基础:Splay 和 Treap 点击查看目录 目录 「学习笔记」平衡树基础:Splay 和 Treap 知识点 平衡树概述 Splay 旋转操作 Splay 操作 插入 \(x\) ...

  5. IDEA-日志管理神器

    Grep Console-插件的好处就在于能使控制台输出日志时,可以直接修改插件中定义好的规则,也可以根据自己定义的规则,输出不同的颜色.这样就可以将错误信息标记成显眼的颜色,方便查看,提高bug寻找 ...

  6. ros系统(1)

    在虚拟机上安装好ros系统之后,打开终端,启动ROS Master,输入roscore命令,结果如下: 再启动小海龟仿真器,输入命令:rosrun turtlesim turtlesim_node,结 ...

  7. MySQL高可用架构-MMM、MHA、MGR、分库分表

    总结 MMM是是Perl语言开发的用于管理MySQL主主同步架构的工具包.主要作用:管理MySQL的主主复制拓扑,在主服务器失效时,进行主备切换和故障转移. MMM缺点:故障切换可能会丢事务(主备使用 ...

  8. Unity实现3D物体遮挡血条

    Unity 实现3D物体遮挡血条 前言:在游戏开发中,我们经常会遇到UI和3D物体的层级遮挡问题,最常见的比如血条跟随敌人的时候,多个敌人的血条会遮挡住玩家或者3D物体,去网上查了一下也没有很好的解决 ...

  9. 手把手带你从0完成医疗行业影像图像检测三大经典模型InceptionV3-RestNet50-VGG16(附python源代码及数据库)——改变世界经典人工智能项目实战(一)手把手教学迁移学习

    目录 1.迁移学习简介 2.项目简介 3.糖尿病视网膜病变数据集 4.考虑类别不平衡问题 5.定义模型质量 6.定义损失函数 7.预处理图像 8.搭建迁移学习网络 VGG16 迁移学习网络 Incep ...

  10. 本地Navicat无法连接服务器mysql8.0

    本地Navicat无法连接服务器mysql8.0 原因: mysql未开启远程连接权限 navivat与mysql密码加密不一致,需一致加密规则 允许远程连接  use msyql; // 1.先查询 ...