Node.js 入门与进阶


简介

1、什么是服务端

什么是服务端:

  • 服务端,又称后端、server 端
  • 前端是用户可见、可操作的部分,如树枝树叶
  • 服务端为前端提供“支撑”和“营养”,如树根

服务端的职责:

  • 提供前端要展示的数据
  • 接收前端要提交的数据
  • 存储数据

服务端的表现形式:

  • 前端 ajax 要调用某个接口
  • 这个接口,就是服务端提供的
  • 如 get 请求获取数据,post 请求提交数据

2、前端和服务端如何交互

  • 前端发起网络请求
  • 服务端接收网络请求
  • 服务端处理并返回数据

服务端处理数据返回前端的返回格式:

  • errno: 0 (即 error number 简写)
  • data: { …… }
  • message: “……”

3、服务端处理并返回数据

  • 定义前端请求的 URL 规则 —— 路由
  • 用 Request 获取数据,用 Response 返回数据
  • 读取和存储数据 —— 数据库

路由是什么:

  • router
  • 作用是定义服务端的入口规则,入口即规则
  • 路由定义 method,如 GET / POST
  • 定义 url 规则,如 /api/list 或 /api/add
  • 定义输入(Request body)和输出(Response body)格式

4、为何选择 NodeJs

  • 开发服务端,有很多种语言可以选择,常见的如 java、python、PHP、.net 等
  • 不同语言都能实现处理 http 请求、定义路由供前端 Ajax 访问、使用数据库存储和查询数据
  • node.js 对于前端工程师的优势
    node.js 使用 JS 语法
    node.js 使用 npm
    学习 node.js 只需要学习框架和 API
  • node.js 已经被普遍应用

一、NodeJs 基础入门

1、NodeJs 是什么

  • 一个基于 Chrome V8 引擎的 JavaScript 运行时(运行环境)
  • 2009 年发布,现已更新到 V14 版本
  • 现已广泛应用于开源社区和各种公司,特别是互联网公司

Chrome V8 引擎:

  • Chrome 是一个浏览器,他可以执行 js 代码
  • V8 就是 chrome 的 js 引擎,以速度著称
  • nodejs 也是基于 js 语法的,因此也可以借用 V8 引擎

运行时:

  • 代码的运行环境
  • 有了运行时,代码才能被执行
  • 没有运行时,代码就是一堆静态文本,就像 txt 一样

NodeJs 出现之前:

  • nodejs 出现之前,只有浏览器可以执行 js 代码
  • 浏览器主要是显示网页,所有的 js 也被当做网页的一部分
  • 除此之外,没有其它应用场景,更不用说做服务端

NodeJs 出现之后:

  • 除了浏览器,nodejs 又是一个新的 js 运行时
  • 哪里安装 nodejs,哪里就可以运行 js 代码
  • 可以用在本机(如使用 webpack 打包),也可以做服务端

如何使用 NodeJs 做服务端:

  • 安装 nodejs
  • 编写 js 代码(处理 http 请求)
  • 使用 nodejs 执行 js 代码

2、NodeJs 下载和安装

node -v
npm -v
  • 使用 nodejs 运行 js 代码
// 在控制台编写执行 js 代码,使用 node 命令进入 js 运行环境
node

// 在控制台输入 node + js文件,是执行该 js 文件的代码
node index.js
  • 安装 cnpm 镜像:
npm install -g cnpm --registry=https://registry.npm.taobao.org
  • Node 升级
// 安装 n
npm install -g n

// 查看版本
n -V

// 安装最新稳定版本
n stable

// or 安装指定版本
n 9.10.0

3、包管理工具 npm

npm 是什么:

  • node package manager,即 nodejs 软件包管理者
  • nom 官网:https://www.npmjs.com/
  • 有几百万的软件包,开源免费

开始使用 npm:

  • npm 会随着 nodejs 一起被安装
  • 通过 npm init 初始化环境
  • 使用 npm install --save lodash 安装 lodash
  • 使用 npm install --save-dev nodemon 安装 nodemon
    使用 node 要手动重启服务,而使用 nodemon 会自动重启服务
"script": {
	"test": "echo \"Error: no test specified\" && exit 1",
	"dev": "nodemon index.js"
}

- -save 和 --save-dev 的区别:

  • --save 是生产环境和开发环境都使用到的包;--save-dev 中的包只在开发环境中使用
  • --save 安装的软件包需要在代码中直接使用,会放在 dependencies 里
"dependencies": {
	"lodash": "^4.17.15"
}
  • --save-dev 安装的软件包不会在代码中直接使用,会放在 devDependencies 里
"devDependencies": {
	"nodemon": "^2.0.2"
}

4、镜像源管理工具

  • Mac 安装
sudo npm install -g nrm
  • Windows 安装
npm install -g nrm
  • 查看版本(验证是否安装成功)
nrm -V

// or
nrm --version
  • 查看可选镜像源
nrm ls
  • 测试哪个源响应比较快
nrm test 镜像源名称
  • 切换镜像源
nrm use 镜像源名称
  • 查看当前正在使用的镜像源
nrm current
  • 增加镜像源
nrm add 镜像源名称 镜像源链接
  • 删除镜像源
nrm del 镜像源名称

5、CommonJS 和 ES6 Module 的区别

ES6 Module 回顾:

  • export default 和 import … from … :一个模块只能有一个 export default
  • export 和 import … from … :export 后面不能直接跟值,必须是声明或语句;导入时的名称不能随便取,必须与导出时的名称一致,且用花括号包裹名称

CommonJS 语法介绍:

  • commonjs 使用 module.exports 输出内容
  • 使用 require(…) 引入内容
  • commonjs 主要用于 nodejs 开发

require(…) 的三个层级:

  • 系统自带模块,如 require(‘http’)
  • npm 包,如 require(‘lodash’)
  • 自定义模块,如 require(‘./utils’);自定义模块一般要写相对目录用于区分
  • require 会先判断是不是系统自带模块,然后再判断是不是 npm 引入的包,最后才判断是不是自定义模块

CommonJS 和 ES6 Module 的区别:

  • 两者的语法不一样
  • commonjs 是执行时引入,是动态的,可以在使用到的地方再引入
  • ES6 Module 是打包时引入,是静态的 ,必须在代码最外层提前引入

为何要使用模块化:

  • 模块拆分开,便于代码的组织和管理
  • 便于多人协作开发,各写各的互不干扰
  • 成熟的语言都支持模块化,如:C、C++、Java、PHP、python等

commonjs 使用示例:

// utils.js
// 单个
function sum(a, b) {
	return a + b;
}

module.exports = sum

// 多个
function sum(a, b) {
	return a + b;
}

function test() {
	console.log("this is test");
}

module.exports = {
	sum,
	test
}
// index.js
// 单个
const sum = require('./utils.js'). // .js 可写可不写

const result = sum(10, 20);

console.log(result);  // 30

// 多个
const { sum, test } = require('./utils');

const result = sum(10, 25);

console.log(result);  // 35
test();  // this is test

6、debug

什么是 debug:

  • bug 即错误
  • debug 即排错,也叫调试
  • 编程语言必须有成熟的 debug 机制,否则将不可用

debug 的重要性:

  • 程序出现 bug 很常见,因此 debug 也很常用
  • 使用 debug 才能快速定位出错的位置

inspect 调试法:

  • 修改 scripts,增加 --inspect,启动服务
// 9229 是默认端口号
"scripts": {
	"test": "echo \"Error: no test specified\" && exit 1",
	"dev": "nodemon --inspect=9229 index.js"
}
  • 打开 Chrome,访问:chrome://inspect,点击页面下方的 inspect
  • 增加 debugger,重启服务,即可调试
// 示例
const http = require('http')

const a = undefined

const server = http.createServer((req, res) => {
	debugger

	const url = req.url
	const path = url.split('?')[0]
	
	a()
	
	res.end(path)
})

server.listen(3000)

7、NodeJs 和前端 JS 的区别

  • 两者都使用 JS 语法
    变量的定义和类型
    函数的定义和执行
    ES6 的 Class Promise 等语法
  • 前端 JS 使用浏览器提供的 Web API
    如前端网页的 DOM BOM 事件 Ajax 等
    前端 JS 可以使用,因为在浏览器环境
    nodejs 则无法使用,因为是 nodejs 环境
  • NodeJs 使用 NodeJs API

二、NodeJs 处理 HTTP 请求

1、认识 Request(req)和 Response(res)

nodejs 启动 web 服务:

  • 使用 http 模块,启动服务
  • 本机的 IP:127.0.0.1
  • 本机域名:localhost

nodejs 如何监听 http 请求:

const http = require('http')

const server = http.createServer((req, res) => {
	// 对监听到的请求进行处理
	
	// 如果此时请求地址为:http://localhost:3000/insex.html
	const url = req.url
	console.log(url)  // 则此处得到的 url 为:/index.html
	
	// res 将服务端的响应返回给前端
	res.end('返回的内容')
})

server.listen(3000)  // 可以监听 http 请求 

3、定义路由

路由包含什么:

  • 路由定义 method,如 GET / POST
  • 定义 url 规则,如 /api/list 或 /api/add
  • 定义输入(Request body)和输出(Response body)格式

nodejs 定义路由:

  • 从 req 中获取 url 和 method
  • 判断 method 是否符合
  • 看 url 是否符合规则

拿到 req 中的 url 和 method:

  • method 中的方法 GET / POST 必须大写
const http = require('http')

const server = http.createServer((req, res) => {
	// 获取到请求地址中的 url
	const url = req.url
	// 这一步是为了去掉 url 中的参数,从而获得真正的 url
	const path = url.split('?')[0]
	// 获取到请求地址中的 method
	const method = req.method

	// 模拟获取信息的 url
	if(path === '/api/list' && method === 'GET') {
		// 命中该 url 后响应
		res.end('响应的内容')
	}

	// 模拟发送信息的 url
	if(path === '/api/create' && method === 'POST') {
		// 命中该 url 后响应
		res.end('响应的内容')
	}
	
	// 不命中 url 后的响应
	res.end('404')
})

server.listen(3000)  // 可以监听 http 请求 

4、querystring

什么是 querystring:

  • http://localhost:3000/api/list?keyword=abc&lang=en&a=120
  • url 问号 ? 后面的都是 querystring(也叫 url 参数)
  • 使用 & 符号分割,以 key=value 的形式存在,可继续扩展

querystring 的作用:

  • 服务端拿到 querystring
  • 根据参数(querystring)的不同,返回不同的内容,实现动态网页
  • 即变化 querystring,就是变换内容(只要服务端支持)
const http = require('http')

const server = http.createServer((req, res) => {
	// 获取到请求地址中的 url
	const url = req.url
	// 这一步是为了去掉 url 中的参数,从而获得真正的 url
	const path = url.split('?')[0]
	// 获取 querystring
	const queryStr = url.split('?')[1] // type=0 或 1
	// 获取到请求地址中的 method
	const method = req.method

	// querystring 解析原理
	const query = {}
	if(queryStr) {
		queryStr.split('&').forEach(item => {
			const key = item.split('=')[0]  // type
			const val = item.split('=')[1]  // 0 或 1
			query[key] = val  // {'type':'0'}
		})
	}

	// 模拟获取信息的 url
	if(path === '/api/list' && method === 'GET') {
		if(query.type === '0') {
			// 当类型为 0 时执行的操作
			res.end('响应的内容')
		}
		if(query.type === '1') {
			// 当类型为 1 时执行的操作
			res.end('响应的内容')
		}
	}
		
	// 不命中 url 后的响应
	res.end('404')
})

server.listen(3000)  // 可以监听 http 请求 

直接使用 nodejs 自带的 querystring:

const http = require('http')
// nodejs 自带的 querystring
const querystring = require('querystring')

const server = http.createServer((req, res) => {
	// 获取到请求地址中的 url
	const url = req.url
	// 这一步是为了去掉 url 中的参数,从而获得真正的 url
	const path = url.split('?')[0]
	// 获取到请求地址中的 method
	const method = req.method

	// 使用 nodejs 自带的 querystring 解析
	const query = querystring.parse(queryStr || '')
	
	// 模拟获取信息的 url
	if(path === '/api/list' && method === 'GET') {
		if(query.type === '0') {
			// 当类型为 0 时执行的操作
			res.end('响应的内容')
		}
		if(query.type === '1') {
			// 当类型为 1 时执行的操作
			res.end('响应的内容')
		}
	}
	
	// 不命中 url 后的响应
	res.end('404')
})

server.listen(3000)  // 可以监听 http 请求 

url 的 hash 是否能起 querystring 同样的作用:

  • hash 不能让服务端获取,以实现动态网页
  • hash 形式:http://localhost:3000/api/list/#/home
  • “#”后面的就是 hash

论:结构化与非结构化:

  • 结构化的数据,易于通过程序访问和分析,如:对象、数组
  • 非结构化的数据,不易通过程序分析,如:字符串
  • 编程中的数据,都尽量结构化

5、res 返回数据

使用 res 设置返回状态码、Content-type、Body:

  • res.writeHead(状态码, 请求头参数)
res.writeHead(200, { 'Content-type': 'application/json' })

如何返回 JSON 数据:

  • res.end() 只能返回字符串形式的内容
  • 字符串的 Content-type 值是: text/plain
const http = require('http')
// nodejs 自带的 querystring
const querystring = require('querystring')

const server = http.createServer((req, res) => {
	// 获取到请求地址中的 url
	const url = req.url
	// 这一步是为了去掉 url 中的参数,从而获得真正的 url
	const path = url.split('?')[0]
	// 获取到请求地址中的 method
	const method = req.method

	// 使用 nodejs 自带的 querystring 解析
	const query = querystring.parse(queryStr || '')
	
	// 模拟获取信息的 url
	if(path === '/api/list' && method === 'GET') {
		const result = {
			errno: 0,
			data: [
				{ username: 'zll', content: 'content1'},
				{ username: 'lgk', content: 'content2'}
			]
		}
		res.writeHead(200, { 'Content-type': 'application/json' })
		// JSON.stringify(result) 将 JSON 转为 字符串形式
		res.end(JSON.stringify(result))
	}
	
	// 模拟发送信息的 url
	if(path === '/api/create' && method === 'POST') {
		const result = {
			errno: 0,
			message: '发送信息成功'
		}
		res.writeHead(200, { 'Content-type': 'application/json' })
		// JSON.stringify(result) 将 JSON 转为 字符串形式
		res.end(JSON.stringify(result))
	}
	
	// 不命中 url 后的响应
	res.writeHead(404, { 'Content-type': 'text/plain' })
	res.end('404 Not Found')
})

server.listen(3000)  // 可以监听 http 请求 

如何返回 html 数据:

  • 设置 Content-type: text/html
  • res.end(…)
  • 浏览器会根据 Content-type 识别出 html 格式
// 示例
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>
`)

6、获取 Request Body

流 stream 数据:

  • 服务端 res.end(),会自动以 流 的形式返回
  • 浏览器会识别到 流,并持续接收信息
  • 待全部接收完,再做处理(视频是一段一段的播放)

演示获取 Request Body:

    // 模拟发送信息的 url
	if(path === '/api/create' && method === 'POST') {
	
		const reqType = req.headers['content-type']
		
		let bodyStr = ''
		
		// req.on('data') 方法用于服务端去识别“流”,并接受数据
		req.on('data', chunk => {
			// chunk 即“流”的每一段数据
			// 拼接每一段流形式完整的数据
			// 这里要使用 toString() 将每一段流转为字符串形式
			bodyStr = bodyStr + chunk.toString()
		})
		// 该方法可以使服务端知道数据传完了
		req.on('end', () => {
			if(reqType === 'application/json') {
				// 将数据转为 JSON 格式
				const body = JSON.parse(bodyStr)
			}

			res.end('接收完成') // 异步
		})

		return
	}

总结

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值