Node.js 基础入门
nodejs 是什么
-
一个基于 Chrome V8 引擎的 Javascript 运行时
- 2009 年发布,现已更新到 V12 版本
- 现已广泛应用于开源社区和各种公司,特别是互联网公司
-
Chrome V8
- chrome 是一个浏览器,它可以执行 js 代码
- V8 就是 chrome 的 js 引擎,以速度著称
- nodejs 也是基于 js 语法的,因此也可以借用 V8 引擎
-
node 出现之前
- nodejs 出现以前,只有浏览器可以执行 js 代码
- 浏览器主要是显示网页,所有 js 也被当做网页的一部分
- 除此之外,没有其他应用场景,更别提做服务端
-
node 出现之后
- 除了浏览器,nodejs 又是一个新的 js 运行时
- 哪里安装 nodejs,哪里就可以运行 js 代码
- 可以用在本机(如使用 webpack 打包),也可以做服务端
-
nodejs 的价值
- 让 js"放飞自我",不再是网页的一部分
- 让 js 可以做更多的事情
- 也让前端工程师可以做更多的事情
nodejs 初体验
- cmd node index.js
const http = require('http')
const server = http.createServer((req, res) => {
const url = req.url // '/index.html?a=100'
const path = url.split('?')[0] //'/index.html'
res.end(path+'-123')
})
server.listen(3000)
npm 介绍
-
node package manager,即 nodejs 软件包管理者
-
软件包有何用
- 现代软件工程已经完善且成熟,项目不会从 0 开始写
- 必须搭配成熟的工具和框架才能满足需求,否则将无人使用
- 每个成熟的开发语言或者环境,都需要成熟的软件包体系
-
开始使用 npm
- npm 会随着 nodejs 一起被安装
- npm init 初始化环境
- npm install lodash --save 安装 lodash
npm 安装 lodash
-
npm init 一路回车 yes
-
npm i lodash --save
-
保证 lodash 在程序中会真正的引用出来,去使用
"dependencies": {
"lodash": "^4.17.21"
}, -
lodash-test/test.js
const _ = require('lodash')
const arr = [1, 2, 3]
const otherArr = _.concat(arr, 4, 5)
console.log(otherArr)
npm 安装 nodemon
- npm install nodemon --save-dev
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev":"nodemon index.js"
},
"devDependencies": {
"nodemon": "^2.0.15"
}
comonjs-回顾 ES6 模块化
- commonjs 语法介绍
- commonjs 和 ES6 Module 的区别
- 为何要使用模块化
commonjs 语法介绍
-
module.exports
-
require(...)
-
主要用于 nodejs 开发
-
require(...)的三个层级
- 系统自带模块,如 require('http')
- npm 包,如 require('lodash')
- 自定义模块,如 require('a')
-
commonjs-test->utils.js
function sum (a, b) {
return a + b
}
function test () {
console.log('this is test')
}
module.exports = { sum, test }
- commonjs-test->index.js
const { sum, test } = require('./utils')
test()
const res = sum(10, 30)
console.log(res)
const http = require('http')//nodejs 自带的模块
const _ = require('lodash')//通过 npm 安装的模块
const { sum, test } = require('./utils') //自己手写的模块
commonjs 和 ES6 Module 的区别
- 两者语法不一样
- commonjs 是执行时引入,动态的
- ES6 Module 是打包(提前)时引入,静态的
为何使用模块化
- 模块拆分开,便于代码的组织和管理
- 便于多人协作开发,各写各的互不干扰
- 成熟的语言,都支持模块化,如 C, C++, Java, php, Python, Go
debug 介绍和演示
- bug 即错误
- debug 即排错,也叫调试
- 编程语言,必须有成熟的 debug 机制,否则将不可用
- debug 的重要性
- 程序出 bug 很常见,因此 debug 也很常用
- 出了 bug,得需要知道代码是如何运行出错的
- 就像一台机器异响,得拆开外壳看看里面如何运转的
- inspect 调试法
- 修改 scrtips,增加--inspect,启动服务
- 打开 chrome,访问 chrome://inspect
- 增加 debugger,重启服务,即可调试
const http = require('http')
// const a = undefined
const server = http.createServer((req, res) => {
// debugger//断点
const url = req.url // '/index.html?a=100'
const path = url.split('?')[0] //'/index.html'
// a()
res.end(path + '1234')
})
server.listen(3000)
console.log('server listening on 3000 port')
nodejs 和前端 js 的区别
-
两者都使用 js 语法
- 变量的定义和类型
- 函数的定义和执行
- ES6 的 Class Promise 等语法
-
前端 js 使用浏览器提供的 Web API
- 如前端网页的 DOM BOM 事件 Ajax 等
- 前端 JS 可以使用,因为在浏览器环境
- nodejs 则无法使用,因为是 nodejs 环境
-
nodejs 使用 nodejs API
- 如处理 http
- nodejs 可以使用,因为是 nodejs 环境
- 前端 JS 则无法使用,.因为在浏览器环境
-
前端 js=js 语法+Web API
-
nodejs=js 语法+nodejs API
-
同样的语法,不同的工作
前后端那些事儿
为何要讲这门课
-
前端和服务端那些事儿
- nodejs 入门和使用
- koa2 框架
- 数据库
- 登录和用户校验
- 综合项目实战
-
企业要求前端工程师,要会写服务端
- 面试时,nodejs 已成为绝对加分项
- 前端工程师的职业发展,离不开服务端
-
企业需求
- 节省人力成本
- 节省沟通成本
- 节省开发时间
-
前端工程师的职业发展,离不开服务端
- 前端不能脱离服务端独立存在
- 做前端开发,必须了解服务端,亲密协作
- 做前端架构师,必须熟悉,甚至引领服务端开发
课程安排
什么是服务端
-
服务端,又称后端,server 端
- 前端是用户可见, 可操作的部分,如树枝树叶
- 服务端为前端提供"支撑"和"营养",如树根
-
服务端的职责
- 提供前端要展示的数据
- 接收前端要提交的数据
- 存储数据 ( 软件公司非常看重数据,会收集各种数据 )
-
服务端的表现形式
- 前端 ajax 要调用某个接口
- 这个接口,就是服务端提供的
- 如 get 请求获取数据,post 请求提交数据
-
前端
- 狭义: 网页
- 广义: 各种客户端,如 App, PC 客户端等
- 本课程中,前端即网页
留言板案例
- 开发前端页面,如用 Vue
- 需要 Ajax 的接口: 获取留言列表,提交留言
- 开发服务端,提供接口
- 小结
- 服务端(后端/server)为前端提供支撑和营养,像一棵树
- 服务端的职责: 提供数据,接收数据,存储数据
前后端如何交互-http 协议
-
前端页面不一定只有一个服务端
-
http 协议-介绍
- 超文本传输协议 HyperText Transfer Protocol
- 规定了客户端和服务端如何通讯
- 是互联网世界数据通讯的标准和基石
-
http 协议-通用
- url : 后端接口的地址,即前端 Ajax 请求时的地址
- method : 请求方法,如 GET POST PUT DELETE 等
- 状态码 : 接口返回的状态, 如 200(成功) 302(重定向) 404(没找到) 500(发生错误)
-
http 协议 - Request
- Request : 请求
- Request Body : 请求是发送给后端的数据
- Request Content-type : 发送数据的格式 , 如 json
-
http 协议 - Response
- Response : 返回/响应
- Response Body : 后端返回给前端的数据
- Response Content-type : 返回数据的格式,,如 json
前后端如何交互-留言板示例
- errno : 0 ( 即 error number 简写 )
- data : { ... }
- message : "..."
前后端如何交互一个页面对应多个服务
- 不同资源可能来自不同的域名
- html 可能来自一个单独的域名
- js css 可能来自一个独立的域名
- 数据可能来自一个独立的域名
服务端如何处理并返回数据
-
定义前端请求的 url 规则--路由
-
用 Request 获取数据,用 Response 返回数据
-
读取和存储数据
-
路由是什么
- router
- 服务端的入口规则
- 和前端的约定
-
路由包含什么
- 定义 method,如 GET/POST 等
- 定义 url 规则,如/api/list 和/api/create
- 定义输入(Request body) 和输出 (Response body) 格式
-
路由和 url
- GET /api/list 路由 -> axios.get( '/api/list?a=1')
- POST /api/create 路由 ->axios.get('/api/create',{...})
- 路由是规则,url 是具体的形式
-
路由-小结
- 规定服务端的入口,入口即功能
- 定义 method,url 规则,输入输出格式
- 路由是规则,url 是具体的形式,两者不同
服务端如何处理数据- req 和 res
-
服务端能得到 Request 和 Response
- 也可简称为 req 和 res
- 通过 Request 可获取: method url body
- 通过 Response : 可设置: 状态码,Content-type,body
-
路由规则的实现离不开 Request
- 先定义路由规则(method,url)
- 通过 Request 可获取: method url
- 检查 method 和 url 是否符合哪个路由
服务端如何处理数据- 数据库
- 数据库,专职做数据的存储和查询
- 数据库是一个独立的系统,不是 nodejs 专属的
- 先不管数据库是什么,就先以为是一个 JSON
为何选择 nodejs 做服务端
- 不同语言,都能实现服务端职责
- 处理 http 请求
- 定义路由,供前端 Ajax 访问
- 使用数据库,存储和查询数据
- 不同语言,有哪些不同
- 语言语法和内置 API
- 框架
- 工具包或软件包(如 npm)
- 初学者学习服务端的重点
- 掌握服务端的流程和套路
- 能快速做出项目,在实践中进步
- 不应该被语言,语法等喧宾夺主
- nodejs 对于前端工程师的优势
- nodejs 使用 JS 语法
- nodejs 使用 npm
- 还需要学习框架和 API
如何学习 nodejs-利用网络
-
学习一门新技术的正确套路
- 第一 , 找准范围
- 第二 , 刻意训练
- 第三 , 及时反馈
-
善用文档
- 程序员每天都会接触新东西
- 必须学会看文档
- 但注意,文档并不适合从 0 入门
Node.js 处理 HTTP
课程介绍
- 定义路由
- 拿到 req 中的 url 和 method
- 定义路由(模拟留言板的获取留言列表,创建留言)
- 测试路由(需要安装 postman)
- querystring
- 获取完整 url
- 从 url 分析 query 参数
- 直接使用 nodejs 自带的 querystring
-
返回数据
- 使用 res 设置返回的状态码,Content-type,Body
- 如何返回 JSON 数据
- 如何返回 html 数据
-
获取 Request Body
- 流 stream 的概念
- 演示如何获取 Request Body
- 使用 postman 测试
认识 req 和 res-监听 http 请求
- nodejs 如何监听 http 请求
- 如何拿到 req 和 res
- 如何使用 req 和 res
- nodejs 启动 Web 服务
- 使用 http 模块,启动服务
- 本机的 IP127.0.0.1
- 本机的域名 localhost
const http = require('http')
const server=http.createServer(()=>{
console.log('已经收到 http 请求')
//还没有返回任何东西
})
server.listen(3000) //可以监听 http 请求
console.log('http 请求已经被监听,3000 端口, 请访问 http://localhost:3000')
认识 req 和 res-获取和使用
const http = require('http')
const server=http.createServer((req,res)=>{
//console.log('已经收到 http 请求')
const url=req.url //http://localhost:3000/index.html
console.log('url is: ',url) // /index.html
res.end('hello world')//res 返回信息给前端
})
server.listen(3000) //可以监听 http 请求
console.log('http 请求已经被监听,3000 端口, 请访问 http://localhost:3000')
路由-定义一个 get 路由
- nodejs 定义路由
- 从 req 中获取 url 和 method
- 判断 method 是否符合
- 看 url 是否符合规则
const http = require('http')
const server = http.createServer((req, res) => {
const url = req.url
const path=url.split('?')[0]
const method = req.method
// console.log('url is: ',url)// /api/list?a=200
// console.log('method is: ',method)
//定义路由: 模拟获取留言板列表
if (path=== '/api/list' && method === 'GET') {
res.end('this is list router')
} else { res.end('404') }
})
server.listen(3000) //可以监听 http 请求
console.log('http 请求已经被监听,3000 端口, 请访问 http://localhost:3000')
路由-定义一个 post 路由
- get 请求,直接拿浏览器访问
- post 请求,需要借助工具--postman
//定义路由:模拟创建留言
if(path==='/api/create' && method==='POST'){
res.end('this is create router')
}
querystring-介绍和使用
-
什么是 querystring
-
nodejs 获取 querystring
-
论结构化与非结构化
- url 问号?后面的都是 querystring (也叫 url 参数)
- &分割,key=value 形式,可继续扩展
-
querystring 的作用
- 动态网页的基石 (hash 就不行)
-
如何利用 querystring 实现动态网页
- 服务端拿到 querystring
- 根据不同的 querystring,返回不同内容
- 即变化 querystring,就是变换内容(只要服务端支持)
const http = require('http')
const server = http.createServer((req, res) => {
const url = req.url
const path = url.split('?')[0]
const queryStr = url.split('?')[1]// a=100&b=200 非结构化
// console.log('queryStr',queryStr)
const method = req.method
// console.log('url is: ',url)// /api/list?a=200
// console.log('method is: ',method)
//解析 querystring
const query = {}
queryStr && queryStr.split('&').forEach(item => {
//item 即 a=100 形式
const key = item.split('=')[0]// 'a'
const val = item.split('=')[1]// '100'
query[key] = val//{a:'100',b:'200'} 结构化
})
// console.log('query is', query)
//定义路由: 模拟获取留言板列表
if (path === '/api/list' && method === 'GET') {
if(query.filterType==='1'){
res.end('this is list router,all')
}
if(query.filterType==='2'){
res.end('this is list router,only mine')
}
// res.end('this is list router') //res 的返回
} else { res.end('404') }
//定义路由:模拟创建留言
if (path === '/api/create' && method === 'POST') {
res.end('this is create router')
}
})
server.listen(3000) //可以监听 http 请求
console.log('http 请求已经被监听,3000 端口, 请访问 http://localhost:3000')
querystring-hash 不能传到服务端
//解析 querystring
const query = {}
queryStr && queryStr.split('&').forEach(item => {
//item 即 a=100 形式
const key = item.split('=')[0]// 'a'
const val = item.split('=')[1]// '100'
query[key] = val//{a:'100'}
})
===========================
const query=querystring.parse(queryStr)
console.log('query is ',query)
querystring-结构化与非结构化
-
结构化的数据,易于通过程序访问和分析,如对象和数组
-
非结构化的数据,不易通过程序分析,如字符串
-
编程中的数据,都尽量结构化
- a=100&b=200 非结构化
- { a : '100', b : '200' } 结构化
-
querystring 是 url ? 后面的参数
-
动态网页的基石 (hash 就不行)
-
nodejs 处理 querystring,并将其结构化
res 返回数据-返回 json 格式
- 使用 res 设置返回的状态码,Content-type,Body
//没有命中路由,默认 404
// res.writeHead(404, { 'Content-type': 'text/plain' })
// res.end('404 Not Found')
res 返回数据-返回 html 格式
const http = require('http')
const querystring = require('querystring')
const server = http.createServer((req, res) => {
const url = req.url
const path = url.split('?')[0]
const queryStr = url.split('?')[1]
const method = req.method
const query = querystring.parse(queryStr)
//定义路由: 模拟获取留言板列表
if (path === '/api/list' && method === 'GET') {
// res.end('this is list router') //res 的返回
//返回结果
const result = {
errno: 0,
data: [
{ user: '张三', content: '留言 1' },
{ user: '李四', content: '留言 2' }
]
}
res.writeHead(200, { 'Content-type': 'application/json' })
res.end(JSON.stringify(result))
}
//定义路由:模拟创建留言
if (path === '/api/create' && method === 'POST') {
// res.end('this is create router')
const result = {
errno: 0,
message: '创建成功'
}
res.writeHead(200, { 'Content-type': 'application/json' })
res.end(JSON.stringify(result))
}
//没有命中路由,默认 404
// res.writeHead(404, { 'Content-type': 'text/plain' })
// res.end('404 Not Found')
res.writeHead(404, { 'Content-type': 'text/html' })
res.end(`
<!DOCTYPE html>
<html>
<head>
<title>404</title>
</head>
<body>
<h1>404 Not Found</h1>
</body>
</html>
`)
})
server.listen(3000) //可以监听 http 请求
console.log('http 请求已经被监听,3000 端口, 请访问 http://localhost:3000')
接收 request body-流
-
获取 Request Body
- 流(stream)
-
下载
- source 即服务端,dest 即客户端(前端)
- 水 即 下载的数据,水管 即 网络 (带宽不确定)
- 下载不仅指大文件,泛指所有的 Response Body
-
浏览器会接收 流(stream)数据
- 服务端 res.end(...) , 会自动以流的形式返回
- 浏览器会识别到 流 ,并持续接收信息(会有进度条)
- 待全部接收完,再做显示或处理 (视频是一段一段的播放)
-
上传
- source 即客户端(前端) ,dest 即服务端
- 水 即 上传的 数据,水管 即 网络 (带宽不确定)
- 上传不仅指大文件,泛指所有的 Request Body
-
服务端如何接收 流(stream) 数据
- 前端使用 Ajax (Postman)提交数据 Request Body
- 服务端需要识别 流 ,并接收数据
- 还要知道何时才能接收完成
代码演示
const http = require('http')
const { chunk } = require('lodash')
const querystring = require('querystring')
const server = http.createServer((req, res) => {
const url = req.url
const path = url.split('?')[0]
const queryStr = url.split('?')[1]
const method = req.method
const query = querystring.parse(queryStr)
//定义路由:模拟创建留言
if (path === '/api/create' && method === 'POST') {
// res.end('this is create router')
const reqType=req.headers['content-type']
let bodyStr = ''
req.on('data', chunk => {//服务端怎么去识别 "流",并接收数据
//chunk 即"流"的每一段数据
bodyStr = bodyStr + chunk.toString()
})
req.on('end', () => {//服务端怎么知道流完了
if(reqType==='application/json'){//json 格式
const body=JSON.parse(bodyStr)
console.log('body is ', body)//对象格式
}
res.end('接收完成')//异步
})
return
}
res.writeHead(404, { 'Content-type': 'text/html' })
res.end(`
<!DOCTYPE html>
<html>
<head>
<title>404</title>
</head>
<body>
<h1>404 Not Found</h1>
</body>
</html>
`)
})
server.listen(3000) //可以监听 http 请求
console.log('http 请求已经被监听,3000 端口, 请访问 http://localhost:3000')





