## 什么是node.js
node.js和JavaScript不完全相同
执行方法
需要在终端中执行代码
读写文件
D:\study\VSCODE代码\node> node day1.js //node 后面加js文件名
//使用require方法加载核心模块
var fs = require('fs');
//读取文件node可以读取文件而浏览器不能读取js hrml css以外的文件
fs.readFile('读取文件.txt', function(error, data) {
console.log(data.toString());
});
//第一个参数是要读文件的路径,第二个参数是回调函数
如果文件读取成功 error :null data为文件内容
如果文件读取失败 error: 错误信息 data:undefined
写入文件:
如果输出成功 error =null 输出错误 error 就是错误信息
可以在终端文件下写入文件 第一个参数是文件地址和文件名 第二个参数是文件内容 第三个是回调函数
// 写入文件 如果输出成功 error =null 输出错误 error 就是错误信息
// 可以在终端文件下写入文件 第一个参数是文件地址和文件名 第二个参数是文件内容 第三个是回调函数
fs.writeFile('data/写入文件.js', '我是写入的文件,又创建了一个文件夹', function(error) {
console.log('文件写入成功');
});
简单的HTTP服务
服务器要干嘛
// 创建一个服务器 提供对数据的服务
//http是一个核心模块
//加载核心模块
var http = require('http');
// 返回一个服务器实例
var server = http.createServer();
// 当客户端收到请求就会自动触发服务器的request请求然后执行第二个参数
server.on('request', function() {
console.log('收到客户端的请求');
});
// 绑定端口号启动服务器
server.listen(3000, function() {
console.log('服务器启动了,可以通过 http://127.0.0.1:3000/来访问');
});
在终端中可以开启服务器 ctrl+c 可以关闭服务器
根据不同请求返回不同响应
server.on('request', function(request, response) {
var url = request.url;
if (url == '/') {
response.end('index page');
} else if (url == '/login') {
response.end('login page');
} else {
response.end('404 not found');
}
});
核心模块
node为JavaScript提供了很多服务器级别的API,这些API绝大多数被包装到了一个具名的核心模块中 例如fs http pash os
require用于加载模块
// os 是炒作系统的Api
var os = require('os');
//获取cpu信息
console.log(os.cpus());
// 获取内存信息
console.log(os.totalmem());
// path 用于处理路径的核心模块
var path = require('path');
path.extname('a/b/c/hello.txt');
执行多个js文件–模块化编程
在js中需要模块化编程 在一个js文件中执行多个js文件
require(‘文件’);require用于在js中调用文件
实例:在核心模块.js中执行核心模块2.js
var http = require('http');
var server = http.createServer();
server.on('request', function(req, res) {
var foo = 'aaa';
console.log(foo);
require('./核心模块2');
})
server.listen(3000, function() {
console.log('服务器可以在http://127.0.0.1:3000/');
});
先输出了aaa 后输出了bbb
、、
、、
、、
、、
在node中只有模块作用域(文件之间不会影响,每个文件中的变量只能自己访问)没有全局作用域
内部无法访问外部
外部无法访问内部
模块作用域可以避免命名冲突
当模块间需要通信时
模块有三种:
1.核心模块:node提供的具名的模块,都有自己的特殊标识: fs(文件操作模块),http(网络服务构建模块),os操作模块(操作信息模块) path路径处理模块
所有核心模块都需要require来加载
2.用户自己编写的文件模快
、、、、、、、、、
、、、、、、、、、、
、、、、、、、、、、、、
、、、、、、、、、、、、、、、、、
、、、、、、、、、、、、、、、、、、
端口号
服务器:24小时不关机的主机
IP:用来定位计算机
端口号:用来定位具体应用程序 (所有需要联网通信时都要端口号)服务器中的软件有各自的端口号,客户端也有端口号和IP地址
一些知名的端口号已经被占用 不要使用 例如80
浏览器对服务器response内容的解析 Content-type设置
1.当服务器发送的是中文
服务端发送的内容是utf8编码的内容
浏览器不知道而是以浏览器默认的gbk编码来解读,解决方法是 服务端告诉浏览器所需要的编码方式
// 当端口号是简体 plain表示普通文本 charset 为编码方式
if (url == '/plain') {
res.setHeader('Content-type', 'text/plain;charset=utf-8'); //设置编码方式
res.end('中文编码');
2.当服务器发送了html
//当端口是html 要想解析html文件:text/html html中如果有中文:charset = utf-8
else if (url == '/html') {
res.setHeader('Content-type', 'text/html;charset=utf-8'); //设置为html编码方式 可以解决乱码问题 但是 html不能被识别出来
res.end('<h1> hello 邓柱沙发 </h1>');
}
、、、、、、、、、、、、、、、
、、、、、、、、、、、、、、、、
、、、、、、、、、、
、、、、、、、、、、、、、、
、、、、、、、、、、、、、、、、
、、、、、、、、、、、、、、、
服务器返回文件中的内容(本质上讲不能发送文件只能发送内容)
服务器是动态读取文件,当文件内容改变时 不需要重启服务器
通过fs.readFile()读取其他文件中的html
data 就是文件中的字符串
var http = require('http');
var server = http.createServer();
var fs = require('fs');
server.on('request', function(req, res) {
var url = req.url;
if (url === '/') {
// 文件位置前是两个点 文件读取时不管位置在哪默认加./
fs.readFile('../resource/index.html', function(error, data) {
if (error) {
res.setHeader('Content-type', 'text/plain;charset=utf-8');
res.end('读取错误');
} else {
//因为data 默认是二进制数据 可以通过 .toString()转化为字符串
//res.end()支持两种数据 二进制 或 字符串
res.setHeader('Content-type', 'text/html;charset=utf-8');
res.end(data);
}
})
}
});
图片读取
var http = require('http');
var server = http.createServer();
var fs = require('fs');
server.on('request', function(req, res) {
var url = req.url;
if (url === '/') {
// 文件位置前是两个点 文件读取时不管位置在哪默认加./
fs.readFile('../resource/index.html', function(error, data) {
if (error) {
res.setHeader('Content-type', 'text/plain;charset=utf-8');
res.end('读取错误');
} else {
//因为data 默认是二进制数据 可以通过 .toString()转化为字符串
//res.end()支持两种数据 二进制 或 字符串
res.setHeader('Content-type', 'text/html;charset=utf-8');
res.end(data);
}
})
}
//读取图片
else if (url == '/image') {
fs.readFile('../resource/1.jpg', function(error, data) {
if (error) {
res.setHeader('Content-type', 'text/plain;charset=utf-8');
res.end('读取错误');
} else {
res.setHeader('Content-type', 'image/jpeg');
res.end(data);
}
})
}
})
server.listen(3001, function() {
console.log('可以在 http://127.0.0.1:3001/来访问');
})
不同的数据类型 Content-type不同,只有字符内容的数据才需要字符编码,图片不需要
也可以在html中的meta设置编码方式
目录列表渲染
读取文件列表 wwwdir
在node中使用模板引擎
1.安装
npm install art-template(该命令在哪里执行 引擎就会被下载到哪里)
2.加载模板引擎
require(‘下载的包的名字’);
3.使用模板引擎:查看引擎文档
一定要先把node modules文件放在js相同的文件夹下
var template = require('template');
var ret = template('被赋值的字符串(必须把data转化为字符串 )',赋值得对象);
在node中使用模板引擎
模板引擎的作用:将原html中的文件通过模板引擎 替换数据 再交给浏览器
1.获取template
var template = require('art-template');
2.在html文件中将要替换的数据用{{}}表示
3.替换
var ret = template.render('被赋值的字符串(必须把data转化为字符串 )',赋值得对象);
模板引擎诞生于服务端
服务器渲染和客户端渲染
客户端渲染 :请求二次以上 ,先加载页面,在加载内容 ,加载快(评论)
客户端渲染不利于seo搜索引擎优化,爬虫爬不到信息,百度等搜索引擎搜不到
服务端渲染: 只请求一次,加载慢(页面),可以被爬虫搜索到 ,利于seo搜索引擎优化
留言板制作(渲染静态页面)
当客户端向服务器发出请求后,服务器会先处理html页面,对于一些 src ,link中的href属性 客户端(服务器)会自动发起请求,如果服务器无法处理就会一直卡着
我们将静态页面HTML都放在view文件夹中 将所有静态资源(第三方资源如css js img等)都放在public当中
什么资源可以访问,什么资源不能访问可以通过代码来控制 // 文件中不用考虑相对路径,因为现在所有资源都是通过url来标识的,只能访问以/public开头的url才能访问public中的内容
comments数组必须在服务器开启外面设置,因为如果放在服务器内,那么每次获取的都是相同的数据,并且每个comments对象都是null-prototype
设置一个comments数组保存留言(先获取数组再替换)
在通过art-template替换内容
var htmlstr = template.render(data.toString(), {
comments: comments
});
res.end(htmlstr);
处理表单get提交
表单html设置
action是请求表单的地址 点击提交后就会请求这个地址
method是请求方法
post get
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210110233954348.png)
点提交后会将name的值放在url中
url核心模块
var url = require('url');
// url.parse('路径');能将路径解析为一个方便操作的对象,第二个参数为true表示直接将查询字符串转化为对象(query)
var parseObject = url.parse(req.url, true);
// parseObject.parthname就得到不包含 查询字符串的路径部分(该路径不包括?之后的内容);
var pathname = parseObject.pathname;
必须放在url的前面
parseObject.query就是得到的表单数据形成的对象:
表单提交重定向
一次请求对应一次响应
步骤:
1.获取表单的数据
var comment = parseObject.query;
comment.dateTime = '2021-1-10';//comment对象中添加dateTime属性
comments.push(comment);
2.重新定向跳转
1.状态码设置为302重定向
res.statasCode
2.在响应头中通过location告诉客户端哪重定向
res.setHeader(‘location’,‘要跳转的url’)
如果服务器的响应的状态码是302就会自动 自动去响应头 location
后面一定要以 res.end()结尾
res.statusCode = 302;
res.setHeader('location', ' / ');
res.end(); //必须要加上
node留言白制作步骤总结
模块系统–基本法则
模块就是文件
使用node编写应用程序主要使用:
1.EcmaScript语言:没有BOM DOM
2.核心模块:
文件操作的fs
http服务的http
url路径操作
path路径处理模块
os操作系统信息
3.第三方模块
art-template
4.自己写的模块
什么是模块化
1.文件作用域
2.通信规则:
加载require
导出
commonJS模块规范
在node中有一个重要的概念:模块系统
· 模块作用域
只能加载一个文件中的变量,即使require了另外一个文件只要该文件不给变量就无法访问
· 使用require方法来加载模块
· 使用exports接口对象来导出模块中的成员
exports是一个对象
导出多个成员就必须是对象
可以通过这个对象添加多个成员 exports.方法得到的是一个对象的形式
exports.a ='123';
exports.d=function(){
console.log('sf')
}
或者用这个方法导出
module.exports = {
add:{}
str='hello'
}
导出单个成员
如果想直接得到某个方法则需要一下形式:
var foo = 'bar';
function add(x, y) {
return x + y;
}
module.exports = add;
以下情况后者会覆盖前者:
exports和module.exports的区别原理
在node中每个模块内部都有一个自己的 module对象
在module对象中有一个exports也是一个对象
var module={
exports:{
}
}
又因为module.exports =exports 所以exports.a == module.exports.a 相当于其实实在 module.exports中添加对象
谁来require这个文件就会得到module.exports
在默认的代码最后都有一句:
return module.exports
优先从缓冲加载
同一个文件如果被两个文件require了 不会重复加载,但是能得到接口对象module.exports
避免重复加载,提高加载效率
require加载规则
模块标识:
1.核心模块 2.第三方模块 3.自定义模块
路径形式的模块
: ./ …/ /xxx
核心模块的本质还是文件
第三方模块
:凡是第三方模块都需用npm下载,用require包名来加载使用,··· 加载原理:先找到当前文件所在目录中的node-modules文件,再找到art-template,再加载package.json文件中的main 如果main中没有内容就会加载index.js文件(当没有package.json文件也会加载index.js)
如果级目录找不到package.js 和 index.js 就到上上一级从新寻找 直到找到为止,否则报错每个项目只有一个node-modules文件
包说明文件
package.json
建议每个demo都需要一个说明文件来进行说明 引用了哪些第三方包(就像说明书一样)
可以通过 npm init
来创建
下载第三方包时加上 --save可以显示版本
会显示第三包的版本信息
如果第三方包被删除了 在 cmd中输入 npm install 会自动下载package.json 中dependency中的所有第三方文件
npm常用命令
npm网站:npmjs.com
可以在cmd中输入npm --version查找版本
升级npm:
npm install – global npm
npm常用命令:
npm install -y可以跳过向导,快速生成
npm install 只下载 一次性将dependencies中的依赖项全部安装
npm install – save包名 下载并保存依赖项(package.json 文件中的 dependencie选项)
npm uninstall 包名 只删除依赖项会保存
npm uninstall --save包名 删除的同时会把依赖项删除
npm --help 查看使用 命令帮助
npm被墙下载过慢问题
解决方式:安装淘宝的cnpm
npm install --global cnpm
–global 不能省略 表示安装到全局 使用cnpm就会用淘宝的服务器下载 jquery
不用下载cnpm使用淘宝镜像源的方法:
npm config set registry https://registry.npm.taobao.org
输入上面代码后 以后用 npm 下载自动用淘宝的镜像下载了
npm config list 查看 registry 地址
express
原生的http在某些方面不足以满足我们的开发需求,所以我们需要用框架来加快开发效率,框架的目的就是提高效率,让我们的代码高度统一
下载:
express的使用
当访问不同的url时不需要再用 if else 中文也不用再 设置
注意是 res.send()结束
var express = require('express');
var app = express();
app.get('/', function(req, res) {
res.send('hello express');
});
app.get('/about', function(req, res) {
res.end('about me');
});
app.listen(3000, function() {
console.log('可以在http://127.0.0.1:3000访问');
});
能自动识别html文件内容
var express = require('express');
var app = express();
app.get('/', function(req, res) {
res.send('hello express');
});
app.get('/about', function(req, res) {
res.send(`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>hello express</h1>
</body>
</html>`);
});
app.listen(3000, function() {
console.log('可以在http://127.0.0.1:3000访问');
});
通过app.use()公开public资源
公开指定目录
app.use('/public/', express.static('./public/'));
这样就可以在网址中访问文件
通过省略/public/来访问,这个时候不能输入/public/某某某
// 开放资源 当use中没有 /public/表示不用加/public/就能访问资源
app.use(express.static('./public/'));
通过自定义别名访问 必须输入/别名/某 来访问某文件 相当于此时a就是public文件夹的别名
app.use('/a/', express.static('./public/'));
这里必须用/a/index.html 来访问public相对路径中的文件
修改完代码自动重启(在VScode中无效)
使用第三方命名航工具:nodemon来解决频繁修改代码重启服务器问题
下载软件方法
npm install – global nodemon
只能在cmd中下载 在vscode中输入下载命令无效
nodemon 会监视文件的变化,当文件发生改变时,自动帮你重启服务器
使用方法:
用
nodemon +js文件名启动服务器
启动的时候如果没有设置换进变量可以在脚本中设置 用npm启动
npm run nodemon app.js
express中的静态资源服务
基本路由
在express中使用art-template引擎(不能在vs code中使用有BUG)
安装art-template
npm install --save art-template express-art-template
必须安装art-template
配置express-art-template(express-art-template是专门用于express中的)
// 配置express-art-template文件,art为要配置的文件类型
app.engine('art', require('express-art-template'));
使用express-art-template
如果配置了模板引擎,express就可以使用render方法
res.render('html模板名',{模板数据});
第一个参数不能写路径默认会在views中寻找改文件,因此将页面文件都放在views文件中
文件后缀名必须是app.engine(‘后缀名’,require())中设置的
如果想要修改render的默认查找路径可以用 app.set(‘名称’,目录路径)
处理数据
在get型表单中通过req.query获取数据
res.redirect(‘路径’)从定向
app.get('/comment', function(req, res) {
//获得数据
var comment = req.query;
comment.dateTime = '2021-1-23-12:00'
comments.unshift(comment);
// 重定向
res.redirect('/');
})
express表单用post请求数据
post常用于处理数据比较多的表单
在express中获得POST表单数据
只能通过第三方bodyParser来获取
1.安装bodyParser插件
npm install --save body-parser
2.配置
var bodyParser = require(‘body-parser’);
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
3.使用
就将req.query改为req.body
app.post('/comment', function(req, res) {
var comment = req.body;
console.log(req.body);
comment.dateTime = '2021-1-23-12:00'
comments.push(comment);
// 重定向
res.redirect('/');
});
crud起步
下载bootstrap模板
到官网复制模板源代码,放到新建的index.html中
下载bootstrap(注意模板用的什么版本就要下载什么版本的bootstrap)
npm install --save bootstrap 或者 npm install --save bootstrap@3.3.7
将模板中的href 链接都改到自己的 public 文件中 和 node_modules文件中
替换数据
从文件中读取数据
fs.readFile中间加了utf-8可以使文件从二进制转化为可识别的代码
JSON.parse(data).students是将data由字符串转化为对象
fs.readFile('./db.json', 'utf-8', function(err, data) {
if (err) {
return res.status(500).send('Sever error');
} else {
res.render('index.html', {
fruits: ['苹果', '香蕉', '花生', '面包'],
// 读取文件data中的数据 data是字符串需要转换为对象 JSON.parse(data)是将data转化为对象,.students是为了赋值
students: JSON.parse(data).students
});
}
路由设计
express中的路由模块的提取
1.用express提供的router来做路由,首先创建一个路由容器
var router = express.Router();
2.把路由挂载在router路由容器中
router.get(’/students’,function(){
)
router.get(’/students’,function(){
);
router.get(’/students/new’,function(){
);
3.在router.js文件中 导出 router
modules.exports=router;
3.将路由挂载到app.js的APP服务中
app.use(router);
app.js是入口模块的职责
router.js路由模块的职责
处理路由
设置具体的函数
模块职责单一,不要乱写
划分模块快的目的为了增强代码的可维护性
提升开发效率
crud处理页面及配置body-parser中间件
bodyparser的配置必须在挂载router之前 及 只能在app.js中 配置,不能在router.js中配置
在文件中添加数据
:
先将文件读取出来,转化为对象,然后往对象中push数据,把对象转化为字符串,再将字符串写入文件
封装提取student数据模块–数据操作文件模块
操作文件中的数据,只处理数据,不关心业务
只是对数据进行增删改查
异步编程
每一个任务有一个或多个回调函数(callback),后一个任务则是不等前一个任务结束就执行,前一个任务结束后,不是执行后一个任务,而是执行回调函数,所以程序的执行顺序与任务的排列顺序是不一致的、异步的。换一种说法就是一个任务分成两段,先执行第一段,然后转而执行其他任务,等做好准备再回过头执行第二段(这个第二段就是我们说的回调)
**fs读取文件就是异步编程 **
封装异步API:访问异步函数的结果,需要用回调函数去访问
如果要获取一个函数中异步操作的结果,则必须通过回调函数来获取
exports.find = function(callback) {
fs.readFile(dbpath, function(err, data) {
// callback中的参数 : 第一个参数是err 成功是null 错误是错误对象 第二个参数是结果 成功是数组 错误是undefined
if (err) {
return callback(err);//如果err出现就回调给callback,callback中执行err的业务
}
//如果没有 err 就执行没err的业务
callback(null, JSON.parse(data).students);
});
}
将student.js引入到router.js中 调用find方法读取文件
var Student = require('./student.js');
router.get('/students', function(req, res) {
// fs.readFile('./db.json', 'utf-8', function(err, data) {
// if (err) {
// return res.status(500).send('Sever error');
// } else {
// res.render('index.html', {
// fruits: ['苹果', '香蕉', '花生', '面包'],
// // 读取文件data中的数据 data是字符串需要转换为对象 JSON.parse(data)是将data转化为对象,.students是为了赋值
// students: JSON.parse(data).students
// });
// }
// });
Student.find(function(err, students) {
if (err) {
return res.status(500).send('Sever error');
} else {
res.render('index.html', {
fruits: ['苹果', '香蕉', '花生', '面包'],
// 读取文件data中的数据 data是字符串需要转换为对象 JSON.parse(data)是将data转化为对象,.students是为了赋值
students: students
});
}
});
})