Node.js 第二节
http 模块
创建web服务器的基本步骤
- 导入http模块
const http = require('http')
- 创建web服务器实例
const server = http.createServer()
- 为服务器实例绑定request 事件,监听客户端的请求
server.on('request',(req,res)=>{
// 只要客户端请求我们的服务器,就会粗发request 事件,从而调用这个事件处理函数
console.log('someone visit our web server!')
})
- 启动服务器
/**
server.listen(端口号,cb调用) 方法,如果端口号为80,可省略
*/
server.listen(80,()=>{
console.log('http server running at http://127.0.0.1')
})
const http = require('http')
const server = http.createServer()
server.on('request',(req,res)=>{
// 只要客户端请求我们的服务器,就会触发request 事件,从而调用这个事件处理函数
// console.log('someone visit our web server!',req,res)
const url = req.url
const method = req.method
// const str = `your request url is ${url},and request method is ${method}`
const str = `您请求的 url 地址是${url},请求的method 类型是 ${method}`
// 为防止中文乱码显示,需在请求头加上 Content-Type
console.log('str',str)
res.setHeader('Content-Type','text/html;charset=utf-8')
res.end(str);//向客户端响应一些内容
})
server.listen(80, () => {
console.log('http server running at http://127.0.0.1')
})
//步骤一、导入需要的模块
// 1.1 导入http模块
const http = require('http')
//1.2 导入fs文件系统模块
const fs = require('fs')
//1.3 导入path 路径处理模块
const path = require('path')
//步骤二、创建基本的web服务器
// 2.1 创建web服务器
const server = http.createServer()
// 2.2 监听web 服务器的request 事件
server.on('request',(req,res)=>{
// 步骤三、将资源的请求 url地址映射为文件的存放路径
// 3.1 获取到客户端请求到的 url 地址
/**
* /clock/index.html
* /clock/index.css
* /clock/index.js
*/
const url = req.url
// 3.2 把请求的url地址 ,映射为本地文件的存放路径
let fpath =''
if(url === '/'){
fpath = path.join(__dirname,'/clock/index.html')
}else{
fpath = path.join(__dirname,'/clock',url)
}
//4.1 根据“映射”过来的文件路径读取文件
fs.readFile(fpath,'utf8',(err,dataStr) => {
//4.2 读取文件失败后,向客户端响应固定的“错误消息”
//4.3 读取文件成功后,将“读取成功的内容” 响应给客户端
res.setHeader('Content-Type','text/html;charset=utf-8')
res.end(dataStr)
})
})
//2.3 启动web服务器
server.listen(80, () => {
console.log('http server running at http://127.0.0.1')
})
moudule
- exports module 与 exports
test.js
exports.name = '会吃鱼的猫'
exports.setName = function(){
console.log('setName')
}
module.exports.sex = 11
// 最终指向 module.exports 指向对象为准
module.exports={
nihao:"1111"
}
module.js
console.log(module)
console.log(module.exports)
console.log(exports)
console.log(exports === module.exports)
const data = require('./test.js');
console.log('data',data);// { nihao: '1111' }
require 得到的永远是 module.exports 指向的对象
npm 与 包
- Node.js 中的第三方模块又叫做包
从 https://www.npmjs.com/ 可以搜索到任何需要的包 - 包管理工具 npm包管理工具
3.4 解决下包速度慢的问题
- 切换npm 的下包镜像源
查看当前的下包镜像源
npm config get registry
将下包的镜像源切换为淘宝镜像源
npm config set registry=http://registry.npm.taobao.org/
- nrm 为了更方便的切换下包的镜像源,可以按照nrm 工具
通过npm 包管理,将nrm 安装为全局
npm i nrm -g
查看所有可用的镜像源
nrm ls
将下包的镜像源切换为 taobao
nrm use taobao
3.5 包的分类
1.项目包分为两类
- 开发依赖包:只在开发期间会用到
npm i 包名 - D - 核心依赖包:在开发期间和项目上线用到的
npm i 包名
2.全局包
全局包会被安装到 C:\Users\wujia\AppData\Roaming\npm\node_modules 目录下。
- 全局安装指定的包
npm i 包名 -g
- 卸载全局安装的包
npm uninstall 包名 -g
注意:
- 只有工具性质的包,才有全局安装的必要性,因为提供了好用的终端命令;
- 判断某个包是否需要全局安装后才能使用,可以参考官方提供的使用说明。
3. i5ting_toc
i5ting_toc 是一个可以把md文档转为 html页面的小工具;
npm install -g i5ting_toc //全局安装包
i5ting_toc -f // 要转化的md文件路径 -o
3.8 发布包:
npm 账号注册成功后,可以在终端中执行npm login 命令,依次输入用户名,密码 邮箱后,即可登录.
注意
在运行npm login 命令之前,必须先把下包的服务器i地址切换为 npm 的官方服务器,否则会导致发布包失败!
将终端切换到包的根目录之后,运行 npm publish 命令,即可将包发布打 npm 上 ( 注意:包名不能雷同)
删除已发布的包
npm unpublish 包名 --force 命令 即可删除
注意:
- npm unpublish 命令 只能删除72 小时以内发布的包
- npm unpublish 删除的包,在24小时内不允许重新发布
- 发布包的时候要慎重,尽量不要往npm 上发布没有意义的包
Express
是一个npm 上的第三方包,提供了快速创建Web 服务器的便捷方法.和Node.js内置的http 模块类似.
http 内置模块用起来很复炸,开发效率低,express 基于欸之http模块进一步封装的.用起来效率高.
对于前端程序员而言,最常见的两种服务器分别是:
- Web网站服务器:专门对外提供 Web 网页资源的服务器
- API 接口服务器: 专门对外提供 API 接口的服务器
使用Express ,我们可以方便,快速的创建 web网站的服务器或 API接口服务器
npm i express@4.17.1
// 1.导入express
const express = require('express')
// 2. 创建 web服务器
const app = express()
// 4. 监听客户端的get 和post 请求 并向客户端响应具体的内容
app.get('/user',(req,res)=>{
res.send({name:"会吃鱼的猫",age:20,sex:'女'});//向客户端发送json对象
})
app.post('/user',(req,res) => {
res.send('请求成功!');//向客户端响应一个文本符串
})
app.get('/',(req,res)=>{
console.log(req.query);//通过向客户端发送过来的查询参数
res.send(req.query);
})
// :参数名 是一个动态的参数
app.get('/user/:id/:name',(req,res)=>{
console.log(req.params);//动态匹配到url的参数
res.send(req.params);
})
// 获取url 中动态参数
// 3. 启动web服务器
app.listen(80,() => {
console.log('express server running at http://127.0.0.1')
})
托管静态资源
- express.static()
非常方便地创建一个静态资源服务器,例如,通过如下代码可以将public 目录下的图片,css文件,javascript文件对外开放.
app.use(express.static('public'))
可以访问public目录下所有文件;
http://127.0.0.1/index.html
http://127.0.0.1/index.js
http://127.0.0.1/index.css
// 4. 快速的对外提供静态资源
app.use(express.static('./clock'))
- 托管多个静态资源目录
多次调用express.static()
app.use(express.static('public'))
app.use(express.static('public'))
访问静态资源文件时,express.static() 函数会根据目录的添加顺序查找所需的文件.
- 挂载路径前缀
app.use('/public',express.static('public'))
http://127.0.0.1/public/index.html
http://127.0.0.1/public/index.js
http://127.0.0.1/public/index.css
1.4 nodemon
这个工具,能够监听项目文件的变动,当代码呗修改后,nodemon会自动帮我们重启项目,极大方便了开发和调试
全局安装
npm install -g nodemon
当基于node.js编写了一个网站应用的时候,传统方式是运行node app.js命令来启动项目,这样做的坏处是:当代码被修改之后,需要手动重启项目.
现在,我们可以将node 命令替换为 nodemon命令,使用nodemon app.js 启动项目,这样做的好处是:代码被修改之后,会被nodemon 监听到,从而实现自动重启项目的效果.
Express 路由
1. Express路由
express 中, 路由指的是 客户端的请求与服务器处理函数 之间的映射关系
Express 中的路由 分3部分组成,分别是
- 请求的类型
- 请求的URL地址
- 处理函数
app.METHOD(PATH,HENDLER)
app.get('/',(req,res)=>{
})
2.模块路由
为了方便对路由进行模块化的管理,Express不建议 将路由直接挂载到app 上,而是推荐将路由抽离为单独的模块.
将路由抽离为单独模块的步骤如下:
- 创建路由模块对应的js文件
- 调用express.Router() 函数创建路由对象
- 向路由对象上挂载具体的路由
- 使用module.exports 向外共享路由对象
- 使用app.use() 函数注册路由模块
index.js
// 1.导入express
const express = require('express')
// 2. 创建 web服务器
const app = express()
//4. 导入路由模块
const router = require('./router.js')
//5. 注册路由模块
app.use(router);//app.use() 函数的作用是 注册全局中间件
// 3. 启动web服务器
app.listen(80,() => {
console.log('express server running at http://127.0.0.1')
})
router.js
var express = require('express')
var router = express.Router()
// 挂载具体的路由
router.get('/user/list',(req,res) => {
res.send('get请求')
})
router.post('/user/list',(req,res) => {
res.send('post请求')
})
// 向外导出路由对象
module.exports = router
Express 中间件的格式
中间件函数的形参列表中,必须包含 next 参数,而路由处理函数中只包含req和res.
app.get('/',function(req,res,next){next()})
- 定义一个最简单的中间件函数
const mw = function(req,res,next){
console.log('这是最简单的中间件函数')
// 把流转关系,转交给下一个中间件或路由
next()
}
const mw1 = function(req,res,next){
console.log('我是mw1')
// 把流转关系,转交给下一个中间件或路由
next()
}
const mw2 = function(req,res,next){
console.log('我是mw1')
// 把流转关系,转交给下一个中间件或路由
next()
}
// 将mv 注册为 局部生效的中间件
app.get('/',mw1,mw2,function(res,req){
res.send('nw1 局部中间件')
})
app.get('/',[mw1,mw2],function(res,req){
res.send('nw1 局部中间件')
})
// 将mv 注册为 全局生效的中间件
app.use(mw)
客户端发起任何请求,到达服务器之后,都会促发中间件.叫做全局生效中间件.
中间件的分类
-
应用级别: 绑定到app实力上的中间件
app.use()、app.get()、app.post() -
路由级别:绑定到express.Router() 实例上的中间件
-
错误级别
专门用来捕获整个项目中发生的异常错误,从而防止项目异常奔溃的问题。错误级别的function 处理函数中,必须有4 个形参,顺序分别是(err,req,res,next)
app.get('/',function(res,req){
throw new Error('服务器内部发生的错误! ');//抛出一个自定义的错误
res.send('nw1 局部中间件')
})
app.use(function(err,req,res,next){
console.log('发生了错误'+err.message);
res.send("Error"+err.message)
})
Express 内置的中间件
- express.static :快速托管静态资源的内置中间件
- express.json:解析json 格式的请求题数据(有兼容性,4.16.0 +)
- express.urlencoded: 解析 URL -encoded 格式的请求体数据(有兼容性,4.16.0 +)
// 1.导入express
const express = require('express')
// 2. 创建 web服务器
const app = express()
// express.json() : 解析表单中发送的json数据
app.use(express.json())
app.post('/',(req,res) => {
console.log('res.body',req.body)
// 解析json
res.send('ok')
})
// 3. 启动web服务器
app.listen(80,() => {
console.log('express server running at http://127.0.0.1')
})
querystring :处理查询字符串
const qs = require('querystring');// Node.js 的内置模块
qs.parse(str);//将查询字符解析为对象
// 1.导入express
const express = require('express')
// 2. 创建 web服务器
const app = express()
const qs = require('querystring');// Node.js 的内置模块
// express.json() : 解析表单中发送的json数据
// app.use(express.json())
// app.use(express.urlencoded({extended:false}))
app.use((req,res,next) => {
let str = ''
// 触发 req的data 事件
req.on('data',function(chunk){
str +=chunk
})
// 触发 req的end 事件
req.on('end',() => {
// str: 存放的是完整的请求体
const body = qs.parse(str);//将查询字符解析为对象
req.body = body // 挂载到body 上
next()
})
})
app.post('/user',(req,res) => {
// 解析json
res.send(req.body)
})
// 3. 启动web服务器
app.listen(80,() => {
console.log('express server running at http://127.0.0.1')
})
抽离中间件:
index.js
// 1.导入express
const express = require('express')
// 2. 创建 web服务器
const app = express()
const com = require('./cmmon_body.js')
app.use(com)
app.post('/user',(req,res) => {
// 解析json
res.send(req.body)
})
// 3. 启动web服务器
app.listen(80,() => {
console.log('express server running at http://127.0.0.1')
})
comom_body.js
// 1.导入express
const express = require('express')
// 2. 创建 web服务器
const app = express()
const qs = require('querystring');// Node.js 的内置模块
app.use((req,res,next) => {
let str = ''
// 触发 req的data 事件
req.on('data',function(chunk){
str +=chunk
})
// 触发 req的end 事件
req.on('end',() => {
// str: 存放的是完整的请求体
const body = qs.parse(str);//将查询字符解析为对象
req.body = body // 挂载到body 上
next()
})
})
module.exports = app