express怎么用?
如何获取请求?
如何处理响应?
如何对向外暴露静态资源?
express核心:中间件:如何理解?javascript
中间件:用来处理 http 请求的一个具体的环节(可能要执行某个具体的处理函数)
中间件通常都是经过修改 req 或者 res 对象来为后续的处理提供便利的使用
中间件分类:
use(function () {req, res, next})
不关心请求方法和请求路径,没有具体路由规则,任何请求都会进入该中间件
use('请求路径', function (req, res, next) {})
不关心请求方法,只关心请求路劲的中间件
get('请求路径', function (req, res, next) {})
具体路由规则中间件
post('请求路径', function (req, res, next) {})
css
// 需求一:用户访问 / 响应 hello world // 需求二:用户访问 /login 响应 hello login // 需求三:将 public 目录开放为相似于 Apache 同样,能够直接经过路径去取访问该目录中的任意资源 const express = require('express') const fs = require('fs') // 1. 调用 express() 方法,获得一个 app 实例接口对象(相似于 http.createServer 获得的 server 实例) const app = express() // 这个就表示是一个中间件 // 目前下面这个 API ,任何请求进来都会执行对应的处理函数 // 不关心当前请求的具体请求方法和请求路径 // 该代码内部若是不发送响应或者作进一步处理则代码会一直停在这里,不会日后执行 app.use(function (req, res, next) { const urlPath = req.path // /puiblic/a.css // /public/main.js if (urlPath.startsWith('/public/')) { const filePath = `.${urlPath}` // 这里加 . 的缘由是由于若是读文件是以 / 开头的则会去当前文件所属磁盘根目录去查找 fs.readFile(filePath, (err, data) => { if (err) { return res.end('404 Not Found.') } res.end(data) }) } else { // 若是请求路径不是以 /public/ 开头的,则调用 next ,next 是一个函数(不肯定) // 这里调用了 next 的目的就是告诉 Express 继续日后执行:中间件 // 具体执行哪一个中间件:取决于对应的中间件的类型 next() } }) // 2. 经过 app 设置对应的路径对应的请求处理函数 // 回调处理函数中: // req 请求对象:用来获取当前客户端的一些请求数据或者请求报文信息 // 例如 req.query 用来获取查询字符串数据 // req.method 用来当前请求方法 // res 响应对象:用来向当前请求客户端发送消息数据的 // 例如 res.write('响应数据') // res.end() 结束响应 app.get('/', (req, res) => { res.write('hello ') res.write('expres') res.end() }) app.get('/login', (req, res) => { // end 用来结束响应的同时发送响应数据 res.end('hello login') }) // 3. 开启监听,启动服务器 app.listen(3000, () => { console.log('服务已启动,请访问:http://127.0.0.1:3000/') })
对于相同请求重复两次,会怎样处理?------对于一次请求来讲,只能响应一次java
express中的中间件
app.use('/public', express.static('开放目录的路径'))
node
在 use 方法中,若是指定了第一个路径参数,则经过req.path
获取到的是不包含该请求路径的字符串
例如当前请求路劲是/public/a.jpg
则经过req.path
拿到的就是 a.jpg
/public/a/a.css a/a.css
目前已知传递给了 static 方法一个绝对路径c:/project/public
假设目前请求是 /public/a/a.css
拿到的 req.path a/a.css
c:/project/public + a/a.cs
拼接起来,读取express
const express = require('express') const fs = require('fs') const path = require('path') const static = require('./middlwares/static') const app = express() app.use('/public', static(path.join(__dirname, 'public'))) app.use('/node_modules', static(path.join(__dirname, 'node_modules'))) app.get('/', (req, res, next) => { console.log('/ 111') res.end('hello') next() }) app.get('/', (req, res, next) => { console.log('/ 222') // 1. 在 http 中,没有请求就没有响应,服务端不可能主动给客户端发请求,就是一问一答的形式 // 2. 对于一次请求来讲,只能响应一次,若是发送了屡次响应,则只有第一次生效 res.end('world') next() }) app.use((req, res, next) => { console.log(111) // 假若有请求进入了该中间件,这里调用的 next 会执行下一个能匹配的中间件 // get / // get /a next() }) // / 111 222 333 // /a 111 use /a // /a next() 111 use/a 222 333 app.use('/a', (req, res, next) => { console.log('use /a') next() }) app.use((req, res, next) => { console.log(222) next() }) app.use((req, res, next) => { console.log(333) }) app.listen(3000, () => { console.log('服务已启动,请访问:http://127.0.0.1:3000/') })
const fs = require('fs') const path = require('path') module.exports = function (dirPath) { // 这里不须要调用 next // 由于若是不是以 /public 开头的,当前这个中间件压根儿就不会进来 return (req, res, next) => { const filePath = path.join(dirPath, req.path) fs.readFile(filePath, (err, data) => { if (err) { return res.end('404 Not Found.') } res.end(data) }) } }
该处理放在前面,要保证其每次发起请求都被执行到,并记录日志json
const express = require('express') const fs = require('fs') const path = require('path') const static = require('./middlwares/static') const app = express() app.use((req, res, next) => { const log = `请求方法:${req.method} 请求路径:${req.url} 请求时间:${+new Date()}\n` fs.appendFile('./log.txt', log, err => { if (err) { return console.log('记录日志失败了') } next() }) }) app.listen(3000, () => { console.log('服务已启动,请访问:http://127.0.0.1:3000/') })
请求方法:GET 请求路径:/ 请求时间:1486537214226请求方法:GET 请求路径:/favicon.ico 请求时间:1486537214735请求方法:GET 请求路径:/ 请求时间:1486537249534 请求方法:GET 请求路径:/favicon.ico 请求时间:1486537250459 请求方法:GET 请求路径:/ 请求时间:1486537253228 请求方法:GET 请求路径:/favicon.ico 请求时间:1486537254353
注意这里这两种中间的所处位置api
const express = require('express') const fs = require('fs') const app = express() app.get('/', function aaa(req, res, next) { // 经过 JSON.parse 解析查询字符串中的某个 try { const data = JSON.parse('{abc') res.json(data) } catch (e) { next(e) } }) app.get('/a', (req, res, next) => { fs.readFile('./dnsajndsja', (err, data) => { if (err) { // 这里调用的 next 会被 app.use((err, req, res, next)) 这个中间件匹配到 next(err) } }) }) app.get('/b', (req, res, next) => { res.end('hello index') }) // 该中间件只有被带有参数的 next 才能调用到 // 带参数的 next 只能被具备四个参数的处理中间件匹配到 // 注意:这里必定要写全四个参数,不然会致使问题 // 这个中间件就是用来全局统一处理错误的 app.use((err, req, res, next) => { const error_log = ` ==================================== 错误名:${err.name} 错误消息:${err.message} 错误堆栈:${err.stack} 错误时间:${new Date()} ====================================\n\n\n` fs.appendFile('./err_log.txt', error_log, err => { res.writeHead(500, {}) res.end('500 服务器正忙,请稍后重试') }) }) // 404 处理中间件 app.use((req, res, next) => { res.end('404') }) app.listen(3000, () => { console.log('running...') })
==================================== 错误名:SyntaxError 错误消息:Unexpected token a in JSON at position 1 错误堆栈:SyntaxError: Unexpected token a in JSON at position 1 at Object.parse (native) at aaa (C:\Users\lpz\Desktop\00-Node-第2天-内容一、内容2\4-源代码\express-demo\app-middleware-404.js:9:23) at Layer.handle [as handle_request] (C:\Users\lpz\Desktop\00-Node-第2天-内容一、内容2\4-源代码\express-demo\node_modules\express\lib\router\layer.js:95:5) at next (C:\Users\lpz\Desktop\00-Node-第2天-内容一、内容2\4-源代码\express-demo\node_modules\express\lib\router\route.js:131:13) at Route.dispatch (C:\Users\lpz\Desktop\00-Node-第2天-内容一、内容2\4-源代码\express-demo\node_modules\express\lib\router\route.js:112:3) at Layer.handle [as handle_request] (C:\Users\lpz\Desktop\00-Node-第2天-内容一、内容2\4-源代码\express-demo\node_modules\express\lib\router\layer.js:95:5) at C:\Users\lpz\Desktop\00-Node-第2天-内容一、内容2\4-源代码\express-demo\node_modules\express\lib\router\index.js:277:22 at Function.process_params (C:\Users\lpz\Desktop\00-Node-第2天-内容一、内容2\4-源代码\express-demo\node_modules\express\lib\router\index.js:330:12) at next (C:\Users\lpz\Desktop\00-Node-第2天-内容一、内容2\4-源代码\express-demo\node_modules\express\lib\router\index.js:271:10) at expressInit (C:\Users\lpz\Desktop\00-Node-第2天-内容一、内容2\4-源代码\express-demo\node_modules\express\lib\middleware\init.js:33:5) 错误时间:Wed Feb 08 2017 15:52:52 GMT+0800 (中国标准时间) ==================================== ==================================== 错误名:Error 错误消息:ENOENT: no such file or directory, open 'C:\Users\lpz\Desktop\00-Node-第2天-内容一、内容2\4-源代码\express-demo\dnsajndsja' 错误堆栈:Error: ENOENT: no such file or directory, open 'C:\Users\lpz\Desktop\00-Node-第2天-内容一、内容2\4-源代码\express-demo\dnsajndsja' at Error (native) 错误时间:Wed Feb 08 2017 15:53:14 GMT+0800 (中国标准时间) ====================================
express官网服务器