用nodejs开发一个后端服务的学习笔记,当初学完后才对很多后端概念有了一个清晰的认识,也算是自己的后端入门笔记,其中对npm、模块的讲解也很值得学习。
2022年4月17日
http模块是node官方提供的核心模块:
普通电脑与服务器的区别:有没有安装 IIS、Apache 这些服务器软件,在node中,http模块就相当于上面那些第三方服务器软件。
2022年4月17日
IP地址:每台计算机的唯一地址,相当于电话号码,点分十进制,格式 a.b.c.d,每一个都是0-255之间的十进制整数。
常见端口号:
2022年4月17日
// 1、导入 http
const http = require('http')
// 2、创建服务器实例
const server = http.createServer()
// 3、绑定 request 事件,监听客户端请求
server.on('request', (req, res) => {
console.log('someone visit our web server')
})
// 4、启动服务器
server.listen(8080, () => {
console.log('server run at http://127.0.0.1:8080')
})
解决响应中文乱码问题:调用res.setHeader(),设置 Content-Type 响应头
res.setHeader('Content-Type', 'text/html;charset=utf-8')
2022年4月17日
直接根据请求url来判断返回的内容就行了,如果想要能在手机上访问,本地启动的IP地址 127.0.0.1(或者localhost)要改成电脑实际的ip地址就可以访问了。
2022年4月17日
注意加上下面这句解决中文乱码的,css会不生效
res.setHeader('Content-Type', 'text/html;charset=utf-8')
2022年4月18日
将一个大文件拆分成独立并互相依赖的多个小模块,如前面的拆分html文件,好处:复用、可维护、按需加载
2022年4月18日
三大分类:内置模块(fs、path、http)、自定义模块、第三方模块(npm),加载模块用 require,会执行加载模块中的代码。加载自定义模块时,可以省略文件后缀名 .js。
2022年4月18日
模块作用域:跟函数作用域类似,在自定义模块中定义的变量、方法,只能在当前模块内访问,防止全局变量污染。
module对象:每一个自定义模块中都有一个 module 对象,里面储存了与当前模块相关 的信息,可以直接在js文件里console.log(module)查看具体信息(当然里面必须要包含 exports 或 module.exports才有用)
2022年4月18日
在自定义模块中可以通过 module.exports 将模块内的成员共享出去,供外部使用
require导入自定义模块时,得到的就是 module.exports 所指向的对象(默认是一个空对象)
2022年4月18日
module.exports 单词太长,为了简化 node 又搞出了个 exports 对象,它和 module.exports 指向同一个对象,console.log(module.exports === exports) 结果为true(当然,这要在初始化默认的状态下才成立,如果后面改变了任意一个的指向,那肯定就不成立了)
2022年4月18日
最终共享出去的对象,永远都是以 module.exports 所指向的对象为准(就是module.exports可以覆盖exports,不管哪个写在前面,反之则不行,此处用覆盖有点不太准确,就是exports可以往里面添加属性,但是不可以直接赋值个新对象去改变module.exports的指向,反过来 module.exports 可以直接指向一个新对象让 exports 不管是添加属性还是赋值的新对象都无效
一开始 module.exports 和 exports 都指向同一个对象,但是如果 module.exports 重新赋值了一个新对象,exports 就被踢到一边凉拌了。
为了避免混乱,在同一个模块中尽量不要同时使用 module.exports 和 exports。
2022年4月18日
node遵循CommonJS模块规范:
2022年4月18日
第三方模块又叫做包
2022年4月18日
2022年4月18日
首次安装包后,目录下会多出 node_modules 和 package-lock.json,不要去改这两个文件下的东西,npm 包管理工具会自动维护。
要安装某个包的具体版本,在包名后面用 @版本号
npm install xx@1.2.3
版本号遵循”点分十进制”,a.b.c,第一位数字代表大版本,第二位数字代表小版本功能版本,第三位代表bug修复。
package.json里记录要安装的包信息,以 ^开头的就是匹配安装第一位大版本的最新版本包,以 ~ 开头的就是要匹配第二位功能版本的最新版本包,没有其他符号的就是直接安装具体版本的包。
2022年4月18日
package.json
npm init -y
文件夹里不能包含中文和空格,否则运行 npm init -y 会报错。
npm install 包名,简写 npm i ,直接用空格分割可以一次安装多个包。-g 全局安装,刚拉下来代码初始化项目时不用跟包名,直接 npm i 会自动根据 package.json 里的配置安装所有的包。
npm uninstall 包名,没有简写,会自动从配置文件里移除。
devDependencies 只在开发阶段用到的包,在安装命令包名前或后加 -D,不知道要安装到哪时,一般根据包的使用文档来安装就行了,规范的包都会直接提供安装命令。
2022年4月18日
默认是从npm官方registry.npmjs.org 下载服务器下载,国内访问国外的节点,需要网络传输需要通过海底光缆,所以慢的很。
淘宝 npm 镜像服务器,每隔一段时间自动同步国外npm官方服务器。
切换 npm 下包镜像源
nrm 小工具,切换镜像源更方便。
2022年4月18日
2022年4月18日
2022年4月18日
获取日的方法是 getDate(),getDay()是获取星期,星期日是0
2022年4月18日
防止用户输入可以直接对标签的 <> 进行转义
2022年4月18日
将使用步骤,示例写出来就可以了
2022年4月18日
2022年4月18日
不管内置模块还是第三方模块,会优先从缓存中加载,内置模块的加载优先级最高,路径里没有 ./ 或 ../,node就会当成内置模块或第三方模块来加载。
用require 加载模块时,如果省略了文件后缀名,node会遵循:
加载第三方模块,会从当前文件父目录下的 node_modules 开始,一级一级向上查找,直到文件根目录。
将文件目录用 require 加载遵循:
2022年4月19日
第三方npm包,web开发框架,和node内置的http模块类似。基于http内置模块封装出来的,功能更强大,开发效率更高。
// 1、导入
const express = require('express')
// 2、创建
const app = express()
// 3、启动
app.listen(80, () => {
console.log('success')
})
2022年4月19日
2022年4月19日
app.use(express.static("public")
外部就可以直接访问public文件夹下的资源,public不会出现在url路径中。如果想要加上路径访问前缀:
app.use('/public', express.static('public'))
要托管多个目录,重复调用上面的方法就可以了,但是查找文件的时候会有个先后顺序,如在第一个目录中找到了相应的文件就不会再去第二个文件夹了。
2022年4月19日
nodemon: 能够监听文件的变动,自动重启项目,方便开发
node xxx.js => nodemon xxx.js
2022年4月19日
路由:就像移动客服的请按 1…,此处就是按键与服务之间的映射。在 express 中就是客户端的请求和服务器处理函数之间的映射关系,由3部分组成:
app.METHOD(PATH, HANDLER)
2022年4月19日
为了方便管理维护,不建议直接挂载到app上
express.Router()
const router = require('./router.js')
app.use(router)
// 添加路由前缀
// app.use('/api', router)
2022年4月20日
跟污水处理厂一样,上一级处理完再交给下一级继续处理。express的中间件,本质上就是一个function处理函数
app.get('/', function(req, res, next) {
next()
})
middleware,中间件函数形参中必须包含 next 参数,而路由处理函数中只包含 req 和 res。
2022年4月20日
全局生效中间件:客户端请求到达服务器之后,都会触发的中间件。通过调用 app.use(中间件函数),即可定义一个全局生效的中间件。
多个中间件之间,共享同一份 req 和 res,可以在上游的中间件中为 req 或 res 对象添加自定义属性,供下游的中间件或路由使用。
2022年4月20日
不用 app.use() 调用,直接加在路由处理中
const mw = (req, res, next) => {
next()
}
const mw2 = (req, res, next) => {
next()
}
app.get('/', 中间件mw, 中间件mw2, (req, res) => {
})
2022年4月20日
2022年4月20日
express官网把常见的中间件用法分成了5大类:
2022年4月20日
2022年4月20日
2022年4月20日
get请求参数通过 req.query 获取
2022年4月20日
post请求参数要通过 req.body 获取,要获取 URL-encoded 格式的请求体数据,必须配置中间件
app.use(express.urlencoded({ extended: false }))
2022年4月20日
跨域:cross-domain,浏览器同源(same-origin)安全机制:协议、域名、端口,浏览器其实已经拿到数据了,只是不会将拿到的数据转交给用户。
cors:主流解决方案 cross-origin resource sharing,由一系列http 响应头组成,这些响应头决定了浏览器是否阻止前端跨域获取资源,只支持 XMLHttpRequest Level2 的浏览器,如 IE 10+、Chrome4+、FireFox3.5+。
jsonp:只支持get 请求。
1、安装cors包
npm i cors
2、导入
const cors = require('cors')
3、使用一下
app.use(cors())
⚠️ 要在路由之前注册,注册的时候要调用一下
2022年4月22日
2022年4月22日
简单请求:需同时满足
预检请求:只要满足以下任一条件,浏览器会先发送 OPTION 请求进行预检,服务器响应成功后才会发送正式请求
2022年4月22日
只能发送get请求,利用 script 标签可以跨域获取资源的历史bug
2022年4月23日
2022年4月23日
database,组织、储存和管理数据的仓库
常见数据库:
1、传统型数据库(关系型数据库、SQL数据库)
2、型数据库(非关系型数据库、NoSQL数据库)
2022年4月23日
2022年4月23日
2022年4月23日
Mac 上 Navicat 连接报错,去系统偏好设置 - MySQL - Initialize Database - Use Legacy Password Encryption
2022年4月23日
Structured Query Language 结构化查询语言,是一门数据库编程语言,只能在关系型数据库中使用
需要额外掌握的4种SQL语法:
2022年4月23日
SELECT * FROM 表名
SELECT 列名[, 列名2] FROM 表名
INSERT INTO 表名 (字段名[, 字段名2]) values (值[, 值2])
# 注意要加 where 条件,否则会更新整张表
UPDATE users SET 字段名 = 新值[, 字段名2 = 新值2] where id = 15
# 注意要加 where 条件,否则会删除整张表
DELETE FROM users where id = 17
2022年4月23日
2022年4月23日
2022年4月23日
SELECT count(*) FROM users
SELECT count(*) FROM users where status = 0
2022年4月23日
2022年4月23日
安装依赖
npm i mysql
项目中使用mysql
const mysql = require('mysql')
const db = mysql.createPool({
host: '127.0.0.1',
user: 'xxxx',
password: 'xxxxx'
database: 'tablename'
})
2022年4月23日
// ? 标识占位符
let insertSql = 'INSERT INTO users (username, password) VALUES (?, ?)'
db.query(insertSql, ['cafehaus', '123456'], (err, result) => {
if (err) return console.log(err.message)
if (result.affectedRows === 1) {
consloe.log('插入成功')
})
// 插入数据便捷写法 SET ?
let info = { username: 'cafehaus', password: '123456' }
let insertSql = 'INSERT INTO users SET ?'
db.query(insertSql, info , (err, result) => {
if (err) return console.log(err.message)
if (result.affectedRows === 1) {
consloe.log('插入成功')
}
})
2022年4月23日
如果只有一个占位符时,可以不用数组,直接写占位符的那个值就行
DELETE FROM 语句一般使用比较少,因为会把数据直接从表中删掉,一般使用标记删除,也就是用 update 去更新某个字段的值来做标记
2022年4月23日
主流web开发模式:
服务端渲染 SSR server side render
2022年4月23日
身份认证:身份验证、鉴权,通过一定的手段,完成对用户身份的确认
2022年4月23日
HTTP 协议的无状态性:客户端的每次 http 请求都是独立的,服务器不会主动保留每次http请求的状态,想象超市的收银员能否记住当前客户是否为vip。
如何突破 HTTP 无状态的限制:超市会为vip客户发放会员卡。
Cookie:储存在用户浏览器中一段不超过4kb的字符串,不同域名下的各自独立,客户端请求时会自动把当前域名下所有未过期的cookie一同发送到服务器。
Cookie存在浏览器,不具安全性,就像客户可以伪造会员卡,所以不要用来存储用户的隐私信息。
Session认证:会员卡(客户端 Cookie) + 刷卡认证。
2022年4月24日
const session = require('express-session')
app.use({
secret:'xxx',
resave:false,
saveUninitialized:true
})
2022年4月24日
session认证机制的不足:需要配合浏览器Cookie使用,Cookie默认不支持跨域访问,跨域需要做很多额外的配置。
最流行的跨域请求认证解决方案:JWT Json Web Token,用户信息通过加密的 Token 字符串的形式储存在客户端浏览器中,服务器通过解密还原 Token 字符串来确认用户信息。
JWT由3部分组成:
2022年4月24日
npm i jsonwebtoken express-jwt
2022年4月27日
windows 上 node 链接 mysql 报错:
Client does not support authentication protocol requested by server; consider upgrading MySQL client
原因:node中的mysql模块不支持 mysql 8 中的 caching_sha2_password 默认的严格加密模式加密方式,所以修改加密规则为普通模式就可以了。
解决方案:
如果后面两条命令输入后显示:Query OK, 0 rows affected (0.01 sec),就是成功了,注意命令后面那个分号不能少。
用终端登录到数据后查看表命令最后的分号后面还要敲一个空格:
show databases;
2022年4月28日
客户端一次请求,服务端两次 res.send 会报错:
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
2022年4月29日
localtunnel 可以将内网服务器暴露到外网,供其他人访问
如果打开网址报错:Invalid Host header,在 vue.config.js 里的开发服务器 devServer 里添加:disableHostCheck: true(是否关闭用于 DNS 重绑定的 HTTP 请求的 HOST 检查,devServer 默认只接受来自本地的请求,关闭后可以接受来自任何 HOST 的请求)。
类似的工具还有:ngrok、frp、nps、nat123。
内网穿透:NAT 穿透,内网也称为局域网,就是路由器搭建的网络,比如需要访问别的站点,就要是公网,我们的普通电脑只有一个局域网ip,没有公网ip,同一局域网内的设备可以通过局域网ip找到你,但是不在这个局域网内的设备则找不到你,最多只能找到你的路由器,但进不了你的局域网,局域网外的设备要访问你就需要内网穿透
JWT认证:在 OAuth2 体系中认证通过后返回的令牌信息分为两大类:不透明令牌(opaque tokens)和透明令牌(not opaque tokens)。
不透明令牌:是一种无可读性的令牌,一般来说就是一段普通的 UUID 字符串。使用不透明令牌时资源服务不知道这个令牌是什么,代表谁,需要调用认证服务器校验、获取用户信息。使用不透明令牌采用的是 中心化 的架构。
透明令牌:一般指的是我们常说的JWT Token,用户信息保存在 JWT 字符串中,资源服务器自己可以解析令牌不再需要去认证服务器校验令牌。使用JWT是属于 无状态、去中心化 的架构。
一旦我们选择了使用JWT,就需要明确一点:在不借助外力的情况下,让JWT失效的唯一途径就是等token自己过期,无法做到主动让JWT失效。非要让JWT有主动失效的功能只能借助外力,即在服务端存储JWT的状态,在请求时添加判断逻辑,这个与JWT的无状态化、去中心化特性是矛盾的。
人人都是码农:AI时代,零基础也能学会编程!关于作者:从美工、前端开发一路成功转型Java后端的野生码农 ,分享UI转前端、前端转Java、全栈开发、AI人工智能和码农搞钱副业...
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。