const fs = require('fs') // 读取文件 // fs.readFile(path[, options], callback) // options:表示以什么编码格式读取文件(可选),不选择时输出为一个Buffer对象 // callback:文件读取完成后通过回调函数拿到读取的结果 fs.readFile('./files/1.txt', 'utf8', (err, dataStr) => { if(err) { return console.log(err) // 若读取成功 err = null,失败则输出一个错误对象 } console.log(dataStr) // 若读取失败则为 undefined }) // 写入内容 // fs.writeFile(file, data[, options], callback) // file:文件路径字符串 // data:写入的内容 // options:表示以什么编码格式写入文件(可选),不选择时输出为一个Buffer对象 // callback:文件写入完成后的回调函数 // 注意点: // 1. 写入文件时文件夹必须存在,文件可不存在,文件不存在时则新建文件 // 2. 重复调用时新写入的内容会覆盖之前的旧内容 fs.writeFile('./files/1.txt', 'Go!', 'utf8', (err) => { if(err) { return console.log(err) // 若写入成功 err = null,失败则输出一个错误对象 } fs.readFile('./files/1.txt', 'utf8', (err, dataStr) => { if(err) { return console.log(err) } console.log('写入的数据为:' + dataStr) }) })
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kehzyTDh-1641905820826)(D:\typora\image-20220108171708425.png)]
// __dirname 表示当前文件所处的目录 const fs = require('fs') fs.readFile(__dirname + '/files/1.txt', 'utf8', (err, dataStr) => { if(err) { return console.log(err) } console.log(dataStr) })
const path = require('path') // 拼接完整路径字符串 // path.join() const pathStr = path.join('/a', '/b/c', '../', '/d', 'e') console.log(pathStr) // 输出 \a\b\d\e,其中'../'会抵消一层路径 const pathStr2 = path.join(__dirname, '/files/1.txt') console.log(pathStr2) // 输出当前路径下所处目录的\files\1.txt // 从路径字符串中解析文件名 // path.basename(path[, ext]) // ext为文件扩展名 const fpath = path.join(__dirname, '/files/2.txt') let fullName = path.basename(fpath) console.log(fullName) // 输出 2.txt let nameWithoutExt = path.basename(fpath, '.txt') console.log(nameWithoutExt) // 输出 2 // 获取路径中文件的扩展名 // path.extname(path) let ext = path.extname(fpath) console.log(ext) // 输出 .txt
URL中的80端口可以被省略,每个端口号不能被多个web服务占用
// 创建web服务器 const http = require('http') // 创建web服务器实例 const server = http.createServer() // 为服务器实例绑定request事件,访问此网页即触发此事件 // req请求对象:在事件处理函数中访问与客户端相关的数据或属性,如req.url 请求url地址(/后面的内容,包括'/') req.method 请求类型 // res响应对象:在事件处理函数中访问与服务器相关的数据或属性 server.on('request', (req, res) => { console.log('Someone visit our web server!') const str = `Your request url is ${req.url == '/'? '根目录': req.url}, and request method is ${req.method}.` // 防止响应乱码 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') })
// 创建web服务器 const http = require('http') const fs = require('fs') // 创建web服务器实例 const server = http.createServer() // 为服务器实例绑定request事件,访问此网页即触发此事件 server.on('request', (req, res) => { const url = req.url // 优化资源请求路径 let fpath = '' if(url == '/'){ fpath = path.join(__dirname, './clock/index.html') } else { fpath = path.join(__dirname, './clock', url) } fs.readFile(fpath, 'utf8', (err, dataStr) => { if (err) return res.end('<h1>404 Not found!</h1>') res.end(dataStr) }) }) // 启动服务器 server.listen(80, () => { console.log('http server running at http://127.0.0.1') })
自定义模块中定义的变量、方法等成员只能在当前模块被访问,这种模块级别的访问限制称为模块作用域。
向外共享模块作用域中的成员需要使用module.exports对象
const username = 'wj' function makeMoney() { console.log('30w') } // 外界使用 require() 方法导入自定义模块时得到的就是 module.exports 所指向的对象 // 其中,使用 require() 方法加载模块属于 CommonJS 规范 module.exports = { username, makeMoney } module.exports.income = '30w' module.exports.go = () => { console.log('go!') } // 以上 module.exports 均可用 exports 替换,默认情况下两者指向同一个对象 // 重点: // 最终共享的结果还是以 module.exports 指向的对象为准 // 注意点: // 1.module.exports = {} 不能使用 exports 代替,因为如果使用 exports = {} 即将exports指向另外一个新的对象 // 2.如需混用最好只使用 module.exports.new1 和 exports.new2 的形式
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gym6xjzc-1641905820828)(D:\typora\image-20220110161005639.png)]
npm config get registry npm config set registry=https://registry.npm.taobao.org/
i5ting_toc -f '要转换的md文件路径' -o
模块在第一次加载后被毁缓存,多次调用 require() 不会导致模块的代码被执行多次。
内置模块的加载优先级最高。
使用 require() 加载自定义模块时必须指定与 ./ 或 …/ 开头的路径标识符,若没有 node 会把它当作内置模块或第三方模块及逆行加载。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LklMRlBx-1641905820828)(D:\typora\image-20220110194741040.png)]
const express = require('express') // 创建web服务器 const app = express() // 启动web服务器 app.listen(80, () => { console.log('express server running at http://127.0.0.1') })
/* app.get('请求URL', (req,res) => { // 处理函数 }) */ app.get('/user', (req,res) => { res.send({name:'wj', income:'30w'}) }) app.post('/user', (req,res) => { res.send('请求成功!') })
app.get('/', (req,res) => { // req.query 查询的是客户端使用 ?name=wj&income=30w 这种字符串形式,默认情况下为 {} res.send(req.query) })
app.get('/:id/:name', (req,res) => { // req.params: URL地址中通过 :参数名 的形式,匹配动态参数值 // :id 中的 id 即为 req.params 对象的属性名 // 请求时直接写 http://http://localhost/256/wj res.send(req.params) // 输出JSON对象 {"id":"256","name":"wj"} })
// 创建一个静态资源服务器 // 访问时不用加 public 这一级,且文件夹可以不叫 public // 也可有多个文件夹被托管,会根据目录的添加顺序查找所需要的文件 app.use(express.static('public')) app.use(express.static('clock')) // 可以在静态资源访问路径之前挂载路径前缀 // 之后如果需要访问 public 文件夹内的文件时必须添加 /public 前缀,前缀可以任意,一般使用目录名 app.use('/public', express.static('public')) // http://http://localhost/public/clock/index.html 才能访问
express路由指的是客户端的请求与服务器处理函数之间的映射关系。
// app.METHOD(PATH, HANDLER) app.get('/user', (req,res) => { res.send({name:'wj', income:'30w'}) }) app.post('/user', (req,res) => { res.send('请求成功!') }) // 以上皆为路由 // 匹配时按照路由的顺序进行匹配
// 路由抽离为单独模块的步骤,以下为模块.js // 创建路由模块对应的 .js 文件 const express = require('express') // 调用 express.Router() 函数创建路由对象 const router = express.Router() // 向路由对象上挂载具体的路由 router.get('/user/list', (req,res) => { res.send({name:'wj', income:'30w'}) }) // 使用 moudule.exports 向外共享路由对象 router.post('/user/add', (req,res) => { res.send('请求成功!') }) // 使用 app.use() 函数注册路由模块 module.exports = router
// 调用 const express = require('express') const app = express() const userRouter = require('./router/router1') app.listen(80, () => { console.log('express server running at http://127.0.0.1') }) // app.use()函数注册全局中间件 // 同时可添加路由前缀,访问时必须加上路由前缀 app.use('/api', userRouter) // 请求时触发 userRouter 内的 get 和 post 方法
中间件的作用:**多个中间件之间共享一份 req 和 res。**基于这样的特性可在上游的中间件中统一为 req 或 res 对象添加自定义的属性和方法,供下游的中间件或路由进行使用。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cxh8Cla3-1641905820829)(D:\typora\image-20220110214414703.png)]
中间件本质:function处理函数
// 中间件函数的形参列表中必须包含next函数,而路由处理函数中只包含 req 和 res app.get('/user', (req, res, next) => { next() }) // next() 表示流转关系转交给下一个中间件或路由 // 定义中间件函数 // 常量 mv 所指向的就是一个中间件函数 const mw = function(req, res, next){ // 中间件函数必须调用next()函数,表示把流转关系转交给下一个中间件或路由 next() }
// 客户端发起任何请求,到达服务器之后都会触发的中间件叫做全局中间件 // 通过调用 app.use(中间件函数) 即可定义一个全局中间件 const mw = function(req, res, next){ // 中间件函数必须调用next()函数,表示把流转关系转交给下一个中间件或路由 next() } app.use(mw) // 流转关系:经过一个中间件后再转交给下一个中间件,若无中间件则转交给路由 // 中间件之间按定义的先后顺序流转 // 简化写法 app.use((req, res, next) => { next() })
// 直接定义在路由中的中间件为局部中间件,只在当前路由中生效 app.get('/about', (req, res, next) => { next() },(req, res) => { res.send('About Page') }) // 可一次性定义多个局部中间件,执行顺序为定义先后顺序 app.get('/', mw1, mw2, (req, res) => {}) app.get('/', [mw1, mw2], (req, res) => {})
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9LjP3Rfl-1641905820829)(D:\typora\image-20220111100358561.png)]
除了错误级别的中间件其他均需在路由之间注册中间件!!!
// 通过 app.use() 或 app.get() 或 app.post(),绑定到app实例上的中间件都叫做应用级别的中间件 app.get('/about', (req, res, next) => { next() },(req, res) => { res.send('About Page') }) app.use((req, res, next) => { next() })
// 绑定到 express.Router() 实例上的中间件叫做路由级别的中间件,express.Router() 为路由实例 const express = require('express') const app = express() const router = express.Router() router.use((req, res, next) => { next() }) app.listen(80, () => { console.log('http://127.0.0.1') })
注意!!!错误级别中间件必须注册在所有路由之后!!!
// 专门捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题 // 且错误级别中间件必须包含四个形参 app.get('/', (req, res) => { throw new Error('Throw a error!') res.send('Home page.') }) app.use((err, req, res, next) => { res.send('Error! ' + err.message) })
// 1.express.static 快速托管静态资源的内置中间件,无兼容性问题 app.use(express.static('public')) // 2.express.json 解析JSON格式的请求体数据,4.16.0+ 版本才可使用 app.use(express.json()) app.post('/user', (req, res) => { // 在服务器端可以使用 req.body 这个属性来接收客户端发送过来的请求体数据 // 默认情况下不加此中间件默认 req.body = undefined console.log(req.body) res.send('ok') }) // 3.express.urlencoded 解析 URL-encoded 格式的请求体数据,4.16.0+ 版本才可使用 // URL-encoded 是一种键值对形式的表单格式 app.use(express.urlencoded({ extended: false })) app.post('/book', (req, res) => { // 默认情况下不加此中间件默认 req.body = {} console.log(req.body) res.send('ok') })
注:
使用postman发送JSON格式请求体数据:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8BMbjPjT-1641905820830)(D:\typora\image-20220111110129048.png)]
使用postman发送URL-encoded 格式请求体数据:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TwyFb0Hi-1641905820830)(D:\typora\image-20220111110100607.png)]
在 express@4.16.0 以前使用 body-parser 第三方中间件解析请求体数据。
const parser = require('body-parser') // 解析 URL-encoded 格式的请求体数据 app.use(parser.urlencoded({ extended: false }))
// 模块化 --> 中间件.js // node.js 内置了 querystring 模块,parse() 专门用来查询字符串。 const qs = require('querystring') function bodyParser(req, res, next) { // 监听 req 对象的 data 时间,来获取客户端发送到服务器的数据 // 若数据量较大无法一次性发完,则客户端会将数据切割后分批发送到服务器端,所以 data 事件可能会触发多次 // 每次触发获取到的数据只是完整数据的一部分,需要手动对接收到的数据进行拼接 let str = '' req.on('data', (chunk) => { // 拼接请求体数据,隐式转换为字符串 str += chunk }) // 当请求体数据接收完毕后会自动触发 req 的 end 事件 req.on('end', () => { // 此时 str 为完整请求体数据 const body = qs.parse(str) req.body = body next() }) } module.exports = { bodyParser } /*-----------------------------------------------------*/ // 调用 --> main.js const express = require('express') const app = express() const myBodyParser = require('./diymw') app.use(myBodyParser.bodyParser) app.post('/user', (req, res) => { res.send(req.body) }) app.listen(80, () => { console.log('http://127.0.0.1') })
// 模块 --> apiRouter.js const express = require('express') const apiRouter = express.Router() apiRouter.get('/get', (req, res) => { const query = req.query res.send({ status: 0, // 状态,0表示成功,1表示失败 msg: 'GET请求成功', // 状态描述 data: query // 需要相应给客户端的具体数据 }) }) module.exports = apiRouter
const express = require('express') const apiRouterPost = express.Router() apiRouterPost.post('/post', (req, res) => { const body = req.body res.send({ status: 0, // 状态,0表示成功,1表示失败 msg: 'POST请求成功', // 状态描述 data: body // 需要响应给客户端的具体数据 }) }) module.exports = apiRouterPost
const express = require('express') const app = express() const apiRouterGet = require('./apiRouter/apiRouterGet.js') const apiRouterPost = require('./apiRouter/apiRouterPost.js') // 注意:获取请求体数据时需要使用中间件对其解析 app.use(express.json()) app.use(express.urlencoded({ extended: false })) app.use('/api', apiRouterGet) app.use('/api', apiRouterPost) app.listen(80, () => { console.log('http://127.0.0.1') })
// 协议、域名或端口号任一项不同就存在跨域问题 // 解决方案 // 1.CORS(跨域资源共享)中间件,一定在路由前注册 // CORS本质就是一些列HTTP响应头 // CORS具有兼容性问题,只有支持 XMLHttpRequest Level2 的浏览器才能正常访问开启了 CORS 的服务端接口 const cors = require('cors') app.use(cors()) /* 扩展: 1.CORS 响应头部 Access-Control-Allow-Origin Access-Control-Allow-Origin: <origin> | * 其中,origin 参数的值指定了允许访问该资源的外域URL res.setHeader('Access-Control-Allow-Origin', 'http://www.baidu.com') 2.CORS 响应头部 Access-Control-Allow-Header 默认情况下,CORS 仅支持客户端向服务器发送如下的 9 个请求头: Accept, Accept-Language, Content-Language, DPR, Downlink, Sava-Data, Viewport-Width, Width, Content-Type 且值仅限于 text/plain, multipart/form-data, application/x-www-form-urlencoded 三者之一 如果客户端向服务器发送额外的请求头信息,则需要在服务器端通过 Access-Control-Allow-Header 对额外的请求头进行声明,否则此次请求失效 res.setHeader('Access-Control-Allow-Header', 'Content-Type, X-Custom-Header') 3.CORS 响应头部 Access-Control-Allow-Methods 默认情况下 CORS 仅支持客户端发起 GET、POST、HEAD 请求 如果需要通过 PUT、DELETE 等方式请求服务器的资源则需要通过 Access-Control-Allow-Methods来指明允许使用的 HTTP 方法 res.setHeader('Access-Control-Allow-Methods', 'POST, GET, DElETE, HEAD') res.setHeader('Access-Control-Allow-Methods', '*') 4.CORS分类 简单请求:GET、POST、HEAD三者之一,且头部信息不超过以下几种并无自定义头部字段 Accept, Accept-Language, Content-Language, DPR, Downlink, Sava-Data, Viewport-Width, Width, Content-Type 预检请求: (1) GET、POST、HEAD之外的请求 (2) 请求头中包含自定义头部字段 (3) 向服务器发送了 application/json 格式的数据 在浏览器与服务器正式通信之前,浏览器会先发送OPTION请求进行预检,以获知服务器是否允许该实际请求,所以这一次的 OPTION 请求称为“预检请求”。 服务器成功响应预检请求后才会发送真正的请求,并且携带真实数据。 */ // 2.JSONP(只支持 GET 请求) // 概念:浏览器端通过 <script> 标签的 src 属性请求服务器上的数据,同时,服务器返回一个函数的调用,这种方式称为JSONP // jsonp 接口 app.get('/api/jsonp', (req, res) => { // 获取客户端发送过来的回调函数名字 const funcName = req.query.callback // 得到要通过 JSONP 形式发送给客户端的数据 const data = { name: 'wj', age: 25 } // 根据前两步得到的数据,拼接处一个函数调用的字符串 const scriptStr = `${funcName}(${JSON.stringify(data)})` // 把上一步拼接得到的字符串响应给客户端的 <script> 标签进行解析执行 res.send(scriptStr) }) /*---------------------------------------------------*/ // jQuery 中 JSONP 请求 $('#btnJSONP').on('click', function () { $.ajax({ method: 'GET', url: 'http://127.0.0.1/api/jsonp', dataType: 'jsonp', success(res) { console.log(res) } }) })
DataType数据类型:
(1)int 整形
(2)varchar(len) 字符串
(3)tinyint(1) 字符串
字段的特殊表示:
(1)PK(Primary Key)主键、唯一标识
(2)NN(Not Null)值不允许为空
(3)UQ(Unique)值唯一
(4)AI(Auto Increment)值自动增长
-- 从 FROM 指定的【表中】,查询出【所有】的数据 -- SELECT * FROM 表名称 SELECT * FROM users; -- 从 FROM 指定的【表中】,查询出指定【字段】的数据 -- SELECT 列名称 FROM 表名称 SELECT username, password FROM users; -- 使用 WHERE 查询 -- SELECT 列名称 FROM 表名称 WHERE 列 运算符 值 SELECT * FROM users WHERE id <> 4; -- 使用 AND 和 OR 运算符 SELECT * FROM users WHERE id <> 2 AND username = 'wj'; SELECT * FROM users WHERE id > 2 OR id < 2; -- SQL语句中关键字(SELECT、FROM等)对大小写不敏感
-- 向指定的表中插入如下几列数据,列的值通过 values 一一指定 -- 列和值要一一对应,多个列和多个值之间使用英文逗号隔开 -- INSERT INTO table_name(列1, 列2, ...) VALUES (值1, 值2, ...) INSERT INTO user (username, password) VALUES ('lmj', '7856');
-- 指定要更新哪个表中的数据 -- 用 SET 指定列对应的新值 -- 用 WHERE 指定更新的条件 -- UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值 UPDATE users SET password = '123789', status = 1 WHERE username = 'lmj01';
-- 从指定表中根据 WHERE 条件删除对应的数据行 -- DELETE FROM 表名称 WHERE 列名称 = 值 DELETE FROM users WHERE username = 'temp';
-- ORDER BY 默认进行升序排序 -- ASC 关键字代表升序排序 SELECT * FROM users ORDER BY status; SELECT * FROM users ORDER BY status ASC; -- DESC 降序排序 SELECT * FROM users ORDER BY status DESC; -- 多重排序 -- 先按照 status 进行降序排序,再按照 username 的字母排序进行升序排序 SELECT * FROM users ORDER BY status DESC, username ASC;
-- 查询 users 表中 status 为 0 的总数据条数 SELECT COUNT(*) FROM users WHERE status = 0;
-- 将列名称从 COUNT(*) 修改为 total SELECT COUNT(*) AS total FROM users WHERE status = 0; -- 普通的列也可以 SELECT username AS uname, password as pwd FROM users WHERE status = 0;