初识
为什么javascript 可以执行
javascript执行要靠解析引擎
chrome-->v8 firefox --> OdinMonkey Safri --> JScore
为什么JavaScript可以操作DOM和BOM
每个浏览器都内置了这些api
JavaScript的运行环境
JavaScript引擎,内置api函数
JavaScript能否做后端开发
可以,需要借助node.js提供后端运行环境
什么是node.js
node.js是基于chrome v8引擎的JavaScript的运行环境
node.js的官方地址:https://nodejs.org/zh-cn/
node.js没有DOM和BOM ajax等api
node.js可以做什么
node.js只提供一些基础的功能和api,都是有许多框架帮助提升
node.js学习路径:javascript基础语法+node.js内置api+第三方好用的api
node.js环境的安装
LTS版本:长期稳定版 current:最新版
查看node.js版本号
win+R+cmd
window终端 命令:node -v
什么是终端
终端(Terminal)专门为开发人员提供的与计算机交互的命令
在node.js环境下执行JavaScript代码
1.打开终端 or shift + 右键
2.命令:node+js文件路径
cd 进入路径
终端快捷键
tab 键快速补全文件路径
esc 键快速清空已经输入的命令
cls 命令清空终端
fs文件系统
fs模块是node.js官方提供的,用于操作文件的模块。他提供了一系列的函数和方法,用于满足用户对文件的操作需求。
const fs = require('fs'); 导入fs文件
fs.readFile() 读取指定文件的内容
fs.readFile(path,[options],callback) path 文件路径 options 表示以什么文件格式读取 callback 回调函数:err,dataStr
读取成功:返回err为null 读取失败:err为错误对象,成功的数据为undefined err.message
fs.writeFile() 写指定文件
fs.writeFile(path,data,[options],callback) data 写入数据 callback:err
文件写入成功:err为null 写入失败:err为一个对象
缺点:只能创建文件,不能创建路径 会覆盖原有的内容
fs模块路径拼接的问题
执行fs读写文件时,是在当前工作目录加上代码路径
解决方案;绝对路径 但是移植性差,不利于维护
__dirname 表示当前文件所在路径
path路径模块
const path = require('path') 导入
path.join() 路径拼接
path.join([path1, path2,.....]) ../会抵消一层路径
path.basename() 在路径字符串中将文件名解析出来
path.basename(path,[ext]) ext 表示文件的扩展名 会删除扩展名
http模块
node.js官方提供,用来创建web服务器的模块。通过http模块提供的http.createServer()方法,就能方便的把普通计算机变为一台服务器
const http = require('http')
普通电脑和服务器的区别就是是否安装了web服务器软件,如IIS、Apache
http模块可以码出一个服务器,不用web服务器软件
ip地址
每个移动设备的唯一id
ping 域名 得 IP地址
127.0.0.1 域名 localhost 回环地址,用于测试
域名和域名服务器
端口号
创建服务器
创建web服务器
1.导入http对象
const http = require('http');
2.创建web服务器实例
const server = http.createServer();
3.为服务器绑定request事件,监听客户端的事件
server.on('request', function(req,res){}); req请求对象 : 客户端发来的数据和属性 res响应对象 :返回给客户端的响应
res.end();添加数据
4.启动服务器
server.listen(port,()=>{}); port 端口号
ctrl + c 停止服务器
响应时的中文乱码
res.setHeader('Content-Type', 'text/html: charset=utf-8');
根据url的不同返回不同的页面内容
1.获取请求的url地址
2.设置默认的响应内容为404 Not Found
3.判断用户请求的是否为/或./index.html
4.判断用户请求的是否为其他html文件
5.设置content-type 防止中文乱码
6.res.end() 响应回客户端
实现clock时钟的web服务器
服务作为资源搬运工
实现流程: 1.导入node模块
2.创建基本的web服务器
3.将资源请求url映射为文件存放路径
4.将读取的内容响应给客户端
5.优化请求路径
模块化
根据来源不同:
内置模块(fs,path, http等),自定义模块,第三方模块(第三方提供的)
加载模块
加载内置模块
const fs = require('fs')
加载自定义模块 .js后缀名可以省略
const 模块名 = require('js文件相对路径')
加载第三方模块
const moment = require('moment')
模块作用域
在自定义内的函数和变量,只能在该模块内被访问,这种模块访问限制,叫模块作用域
向外共享模块作用域中的成员
每一个自定义模块内部都有一个module对象,他储存当前模块相关内容 (path 模块路径 filename文件名 exports 文件接口)
module的exports对象 可以省略module
自定义模块可以通过module.exports,将模块内成员共享出去,共外界使用,外界使用require方法,返回的是exports对象
exports 和 module.exports 的使用误区
不建议在一个模块内使用module.exports 和 exports 同时使用
CommonJs的标准
1.每个模块内module代表本模块
2.exports是module的属性,对外的接口
3.require返回为exports指向的对象
包和模块
npm与包
node.js 中第三方模块叫做包
node.js 中的包都是免费开源的
包基于内置模块开发出来的
包共享搜索网站:https://www.npmjs.com/
包下载网站:https://registry.npmjs.org/
下载包:
包管理工具 Node package Manager
npm install +包的完整的名字
简写指令:npm i +包的完整的名字
npm i +包的完整的名字@版本号 下载对应版本的包
新下载的版本会覆盖已有版本
版本:大版本.功能版本.Bug修复
前面的版本号变化,后面归零
卸载包
npm uninstall +包的名字
查看当前下包的镜像源 原来的镜像:https://registry.npmjs.org/
npm config get registry
将下包的镜像源切换为淘宝的镜像源
npm config set registry=https://registry.npm.taobao.org
检查镜像源是否下载成功
npm config get registry
查看包的使用:https://www.npmjs.com/
初次装饱之后,或有node_modules文件 和 package-lick.json配置文件:packages记录下载的包的信息
程序员不须要去管理node_modules文件 npm 会自动管理
包管理配置文件
项目的名称,版本号,描述
项目中用了那些包
多人协作问题
防止包的重复传输,一定把node_modules添加.gitignore文件中
之后在根目录下快速建立一个package.json 命令:npm init -y 只需要执行一次 该命令只能在英文的根目录下才可以运行
一次性下载所有包
npm i or npm install 读取dependencies中的所有的包
开发时用的包 发布不要的 添加到devDependencies 命令:npm -i 包名 -D 全写:npm install 包名 --save-dev
包的分类
开发依赖包devDependencies
核心依赖包dependencies
npm install 包名 -g 配置全局包 位置:C:\Users\Administrator\AppData\Roaming\npm
npm uninstall 包名 -g
i5ting_toc包(全局)
将md文件转化为html文件的工具
i5ting_toc -f md文件路径 -o 会产生一个preview文件
包的规范
包必须以独立目录存在
包的顶级目录下要包含package.json
package.json必须包含name version main:包的入口 require函数会调用这个入口
初始化包的基本结构
1.建个根目录
2.建package.json(配置文件) index.js(入口函数) README.md(说明文档)
通过markdown写.md文件
模块的加载机制
require函数默认优先从缓存中加载,
内置模块的加载机制最高,如果和内置模块重名,优先返回内置模块
自定义加载机制必须有./ 或../
require没有后缀名,1.按文件名加载 2.补全.js 3.补全.json 4. 补全.node 5.报错
第三方模块加载机制:1.在当前require所在目录中找node_modules 2.向上查找
目录作为加载对象时,1.找package.json 中 main 2. 没有main 找index.js 3.没有package.json 或 没有main 和 index.js 报错
express
初始express
express是基于node.js平台的快速,极简创建web服务器
导入
const express = require('express');
创建web服务器
const app = express();
调用app.listen(port,callback);启动服务器
app.listen(port,function(){});
监听GET请求 POST请求
app.get(url,function(req,res));
url:客户端请求的url地址 callback:请求对应的处理函数 req请求对象 res响应对象
app.post(url,function(req,res){});
把内容响应给客户端
res.send();
获得客户端发送的查询字符串
req.query 返回对象
获取动态参数 动态参数为冒号(:)后面的数据
req.params 返回对象
express快速托管静态资源
express提供了一个非常好用的函数,express.static() 通过它,我们可以创建一个静态资源服务器,通过app.use()是文件可以对外访问
app.use(express.static(目录路径));
托管多个静态资源
调用多次use和static函数 有先后顺序,先添加的先查找
挂载路径前缀
app.use('public', express.static(目录)); /public/index.html
nodemon 方便程序员的开发和调试,不需要频繁的close项目
使用nodemon
nodemon 项目.js 使用nodemon监听项目
express路由精简项目结构
express的路由是客户端的请求和服务器函数之间的映射关系
express的路由的构成:请求的类型、请求的url和处理函数
路由格式:app.请求的类型(url,function(req,res){
res.send();
})
路由的匹配过程
按照路由顺序会进行匹配,如果url和请求类型都成,才会返回给对应函数
模块化路由
express不建议我们直接挂在app对象上
步骤: 1.创建.js文件
2.express.Router()函数创建路由对象
3.向路由对象挂在具体路由
4.使用module.exports向外共享路由对象
5.使用app.use()函数注册路由模块
为路由模块挂在统一前缀
app.use('路径',router);
常见express中间件
中间件,中间处理函数
express的中间件格式
中间件处理函数必要包含req,res,next函数 而路由函数 只包含req,res
app.get('/', function (req, res,next){
next();不用实化为特定函数
});
全局生效的中间件
客户器发起的任何请求都会触发的中间件,叫做全局中间件
调用app.use(中间件函数) 就可以产生一个全局生效的中间件
中间件可以预准备数据 一份req和res
客户端的请求会按照定义先后顺序响应
局部生效的中间件
app.get('/',局部中间件函数名1,函数名2,....,function(req, res){}); 优先中间件,再路由处理函数
app.get('/',[函数名1,函数名2,....],function(req, res){});
中间件的使用注意事项
1.中间件必须在路由的前面注册
2.客户端发送的请求,可以连续调用多个中间件进行处理
3.执行完中间件函数之后,不要忘记调用next()函数
4.调用完next()之后,不要在写其他的代码了
5.连续调用多个next()时,共享req和res
中间件的分类
1.应用级别的中间件
绑定到app上的中间件
2.路由级别的中间件
绑定到express.router
3.错误级别的中间件
专门捕获项目中出现的错误 格式(err,req,res,next) 捕获throw出的中间件 中间件必须在路由之后
4.express内置中间件
express.static 快速托管静态资源的
express.json 解析json格式的请求体数据 仅4.16.0之后
格式:app.use(express.json()) 表单数据在req.body
express.urlencoded 解析URL-encoded格式的请求体数据 仅4.16.0之后
格式:app.use(express.urlencoded({extended:false}))
5.第三方中间件
第三方发布的
步骤: 1.npm install body-parser 下载
2.使用require导入中间件
3.调用app.use()注册并使用中间件
自定义中间件
1.定义中间件
2.监听req的data
3.监听req的end
4.使用querystring内置模块解析数据
5.解析出来的数据挂载到req.body
6.把自定义中间件封装成模块
使用express创建api接口
api模块
1.创建express服务器
2.创建api路由模块
const aoiRouter = express.Router;
3.挂载路由
4.暴露给外部
编写GET接口
apiRouter.get('/',(req, res) => {
获得客户端的请求
const query = req.query
res.send({
status: 200, 状态码
msg:'请求成功', 状态信息
data:query 返回给客户端的数据
})
})
编写POST接口
const body = req.body
res.send({
status: 200, 状态码
msg:'请求成功', 状态信息
data:body 返回给客户端的数据
})
express跨域问题
express中启用cors跨域资源共享
1.cors
express的第三方中间件
1. npm install cors
2.const cors = require('cors')
3.app.use(cors())
cors是由一系列http响应头组成
cors的响应头部
1.Access-Control-Allow-Origin:具体的域名|*
res.setHeader('Access-Control-Allow-Origin', '*')
2.Access-Control-Allow-Headers:仅限于九个响应头(Accept,Accept-Language,Content-Language,DPR,Downlink,Save-Data,Viewport-Width,width,Content-Type)
需要添加请求头,必须添加:res.setHeader('Access-Control-Allow-Headers', '添加的响应头');
3.Access-Control-Allow-Methods:默认支持GET、POST和HEAD
res.setHeader('Access-Control-Allow-Methods', 'GET,POST,HEAD,DELETE');
cors请求分类
简单请求;请求方式和请求体简单
预检请求:预检请求发两次请求
2.jsonp
jsonp接口,先定义jsonp接口
步骤; 1.获取客户端发送过来的回调函数名字
2.得到要通过jsonp形式发送给客户端的数据
3.根据前两步得到的数据,拼接出一个函数调用的字符串
4.把上一步拼接得到的字符串,相应给客户端的script标签进行解析
session和jwt认证
服务器渲染:session认证机制
cookie;存储在用户浏览器的一段不超过4kb的字符串,它有一个名称,一个值和几个用于控制cookie有效期,安全性,使用范围的可选属性组成
1.cookie自动发送
2.域名独立的
3.过期失效
4.4kb限制
express的session认证
1.安装express-session
npm i express-session
2.配置代码
var session = require('express-session')
app.use(session({
secret: 'keyboard cat', secret 属性值可以为任意字符
resave:false, 固定写法
saveUninitialized:true 固定写法
}))
3.向session中存数据
app.post('/',(req,res)=>{
if(req.body.username != 'admin' || req.body.password !== '00000000'){
return res.send({
status:1
msg:'登录错误'
})
}
req.session.user = req.body 将用户信息存入到session中
req.session.islogin =true 将用户的登录状态填入session中
res.send({
status:0,
msg:'登录成功'
})
})
4.向session中取数据
app.get('/',(req,res)=>{
检查是否已经登录
if(!req.session.islogin) {
return res.send({
status:1,
msg:'fail'
})
}else{
res.send({
status:1,
msg:'success',
username:res.session.user.username
})
}
})
5.清空session
推出登录操作
app.post('/',(req.res)=>{
清空session数据
req.session.destroy()
res.send({
status:0,
msg:'success'
})
})
session不支持跨域认证
前端分离:JWT认证机制
jwt 组成部分:header头部 payload 有效载荷 signature 签名 三者用'.'分隔 payload 为真正的用户信息
jwt字符串:储存在localStorage或sessionStorage 建议放在authorization头部字段中
格式:Authorization:Bearer <token>
安装jwt
npm i jsonwebtoken express-jwt
jsonwebtoken:用于生成jwt字符串
express-jwt:用于将jwt字符串解析还原为JSON对象
定义secret密钥
作用:1.通过密钥对用户信息加密 2.通过密钥对于token解密
const secretKey ='任意字符串'
登录之后生成jwt字符串
app.post('/',(req,res) => {
res.send({
status: 200,
message:'登录成功'
参数1:用户信息对象
参数2:加密的密钥
参数3:配置对象,可以配置token的有效期
token:jwt.sign({username:userinfo.username},secretKey,{expiresIn:'30s'}) 30s为有效期
})
})
将jwt转化为json对象
var { expressjwt:jwt } = require("express-jwt")
expressJWT 解析token 会把解析出来的数据挂载到req.user req.auth
unless 那些路径不需要访问权限
app.use(expressJWT({secret:secretKey}).unless({path:[/^\/api\//]}))
用req.user获取用户信息
捕获JWT失败后产生的错误
token 失效或过期
app.use((err,req,res,next)=>{
if(err.name === 'UnauthorizedError') {
return res.send({
status:401,
message:'fail'
})
}
res.send({
status:500,
message:'未知错误'
})
})