npm init//创建管理文档
npm i express -S //-S表示在生产环境下也要用到的包
var express = require('express');//导出express的顶级函数
var app = express();//创建express对象
app.get('/', function(req, res){//监听get请求的'/'地址
res.send('ok')//向客户端传送回'ok'字符串
})
app.listen(8080, function(){//监听8080端口,
console.log('http://localhost:8080');
})
是不是很简单,下面开始第一个拓展。
简介:express的static静态方法用于托管静态文件的请求,比如css,img,js,font等文件的请求,因为nodejs和其他服务器不一样,不会默认有读取文件并传给客户端这个功能,所以需要这个方法来自动读取并传送静态文件。
使用:
下面指的是所有静态文件的请求都到app.js的工作目录的里去寻找并加载并送到客户端
app.use(express.static('./'))
下面两种指的是所有静态文件的请求都到app.js下的views的文件夹里去寻找、加载、输送到客户端
app.use(express.static('views'))
app.use(express.static('./views'))//root填的路径不可以用/开头的形式
如果用绝对路径,也就是'/'的形式,其会去系统根路径下寻找静态文件,也就找不到我们需要的文件了
举个例子:
如果:app.use(express.static('./'))
请求:http://localhost:8080/index.html时,会去app.js的文件的目录下寻找index.html,读取并送回客户端
如果:app.use(express.static('views'))
请求:http://localhost:8080/index.html时,会去app.js的下的文件目录'views'下寻找index.html,读取并送回客户端
它会把原本的http://localhost:8080/index.html在后台变为http://localhost:8080/views/index.html
其对css,img,js,font等文件也不例外,如果index.html中link了一个css文件
第二个例子:
//index.html文件
<link rel="stylesheet" href="/index.css" />// 和static函数中的不一样,这里'index.css','/index.css','./index.css'都可
//app.js文件
app.use(express.static('./'))
请求:http://localhost:8080/index.html时
//过程:服务端先从app.js的文件的./目录下寻找index.html,读取并送回客户端
//浏览器先解析HTML代码,构建DOM树
//构建过程中遇到lnik会阻塞html的解析,并会从服务端请求'index.css'
//由于设置了静态文件目录
//这时会去app.js的文件的./目录下寻找index.css,读取并送回客户端,浏览器加载并解析,
//如果后面没有js标签,link进来的css的加载和解析是不会的阻塞构建dom树的,但是会阻塞页面渲染
(内联css会阻塞dom树构建)
(如果下文有外链js标签,不会阻塞js加载,会阻塞js解析,而js会阻塞dom构建)
(完了我感觉跑题了)
//同时解析html并同时构建dom树
//dom树和css树解析完毕,组合成渲染树
//对渲染树进行Layout操作,渲染绘制整个页面
感觉怎么关联了其他知识点。。没事知识点连起来很重要的。。
下面是第一个拓展的注意点:很多时候link中 href=""填相对路径与绝对路径会出现请求差异。
直接上例子:
/views/index.html文件
<link rel="stylesheet" href="./index.css" />
/index.css文件
/app.js文件
app.use(express.static(./'))
//它会请求不到css文件,为什么呢
//请求http://localhost:8080/views/index.html来获取index.html时,找到app.js文件目录下的views文件夹,确实找到并读取传输了index.html文件
//但是这时候浏览器的url为http://localhost:8080/views/index.html,如果这时候去请求为相对路径的index.css
//会将link href="./index.css" 中的'./index.css'加上浏览器原本的url,最终请求的url变为
http://localhost:8080/views/index.css
//http://localhost:8080/views/index.css加上express.static(./')中的'./'还是原来的http://localhost:8080/views/index.css
//而在这个路径中根本找不到index.css文件,因为它在http://localhost:8080/index.css中,所以会请求失败
//如何才能请求到这个index.css文件呢,把它的link href改成绝对路径'/index.css'
//这时候与浏览器的地址相加为http://localhost:8080/index.css,就可以请求到了,绝对路径不关心现在的浏览器url地址为何
第二个例子:
/views/index.html文件
<link rel="stylesheet" href="../public/css/index.css" />
/public/css/index.css文件
/app.js文件
app.use(express.static('views'))
//请求http://localhost:8080/index.html
//也是找到了index.html,找不到index.css文件
//因为http://localhost:8080/index.html +../public/css/index.css为http://localhost:8080/public/css/index.css
//http://localhost:8080/public/css/index.css再加上./views就变成http://localhost:8080/views/public/css/index.css
//<link rel="stylesheet" href="../public/css/index.css" />不管怎么写,最后都会加个'./views'也就是再views文件夹下寻找
//自然找不到了
要是我一定要让上面目录结构的index.html能访问到index.css呢
看第三个例子:
/views/index.html文件
<link rel="stylesheet" href="/css/index.css" />
/public/css/index.css文件
/app.js文件
app.use(express.static('views'))
app.use(express.static('public'))
//可以多加几条express.static,先找第一条如果用第一条没找到就用第二条规则寻找,都找不到就404
//所以过程是这样的
//请求http://localhost:8080/index.html
//http://localhost:8080/index.html + views等于http://localhost:8080/views/index.html就找到了index.html
//随后寻找index.css //http://localhost:8080/index.html+"/css/index.css" +'views' 等于http://localhost:8080/views/index.css所以找不到
//第一条找不到,就使用第二条规则寻找
//http://localhost:8080/index.html+"/css/index.css" +'public' 等于http://localhost:8080/public/index.css
//与index.css路径相符,所以就找到了
总的来说,静态文件的src 与 href使用绝对路径更加合适,用了绝对路径后,就算把html文件放在任何地方,都可以访问到。
但是,问题又来了,之前我们是通过在项目根目录中用命令行执行的app.js,如果我们从通过在views/中打开命令行,再用命令node …/app.js 执行它,打开浏览器,这时候发现连html文件都找不到了,这是为什么呢。
原来express.static中的路径的根目录是基于命令行的工作目录的,也就是说这时候请求//请求http://localhost:8080/index.html加上的app.use(express.static(‘views’))中的路径不再是 ‘views’,而是基于命令行的工作目录的下的views目录,也就是/views/views这个目录了,这个目录下当然没有html文件。
如果一定要在这个结构下正常访问,则将express.static(‘views’)改为express.static(’./’),把express.static(‘public’)改为express.static(’…/public’)就行了,但是这样改来改去是不是很麻烦。
这时候我们又想起刚开始说的如果express.static()中放入绝对路径的话就会按系统绝对路径确定静态文件目录。
nodejs中有两个变量,一个是__dirname,一个是__filename,前者表示文件所在目录的绝对路径,后者表示文件本身的绝对路径。
如果将__dirname+'views’放入express.static()中,则会固定静态文件路径,不受命令行的工作目录影响
let path = require('path')//使用path.join智能拼接url字符串
app.use(express.static(path.join(__dirname, 'views')))
app.use(express.static(path.join(__dirname, 'public')))
这时候访问http://localhost:8080/index.html,都可以成功
但这时候问题又来了,每次请求css文件的时候都会去views和public文件下都搜寻一次,浪费了服务器资源,什么方法可以页面文件去views目录下找,css文件去public找呢,这就得找app.use方法了。
app.use(’/abc’)方法的含义是所有以’/abc’开头的url请求都会经过这个中间件,如果没有设置则所有请求都会经过use方法。
那么我们便这样设置
app.use('/views',express.static(path.join(__dirname, 'views')))
app.use('/public',express.static(path.join(__dirname, 'public')))
表示开头为/views的url在views文件下查找
开头为/public的url在public文件下查找
这时候问题终于没了
option到时候按照以对象的形式传入express.static,
如app.use(’/public’,express.static(path.join(__dirname, ‘public’),{
dotfiles: ‘allow’
}))
下面对每个选项解释一下
dotfiles:对以点开头的文件的请求处理
“allow” - 对dotfiles没有特殊处理,直接允许。
“deny” - 拒绝对点文件的请求,回复403,然后调用next()进入下一个中间件。
默认“ignore” - 就像dotfile不存在一样,回复404,然后调用next()进入下一个中间件。
etag:
浏览器会根据HTTP请求的ETag验证请求的资源是否发生了改变,如果它未发生变化,服务器将返回“304 Not Modified”响应,并且资源从浏览器缓存中读取,这样就不必再次下载请求。
默认true:启用。
false:关闭
extensions:
设置文件扩展名回退:如果找不到文件,请搜索具有指定扩展名的文件并提供找到的第一个文件。
示例:['html', 'htm']。比如设置html后请求的是/views/a.asd,它在里面找不到相关文件就会返回/views/index.html文件
默认false:关闭这个功能
['htm', 'html']:如果找不到请求的文件则返回第一个找到的htm或者html文件
fallthrough: 打印并返回具体的错误
false:返回具体错误
默认true:不打印和返回具体错误
immutable:
immutable在Cache-Control响应头中启用或禁用该指令。
如果启用,maxAge还应指定该选项以启用缓存。
该immutable指令将阻止受支持的客户端在maxAge选项的生命周期内发出条件请求,以检查文件是否已更改
true:客户端来第二次请求的时候返回文件未更改,且在maxAge设定的时间内不再检查服务端文件是否更改,直接调取本地的缓存
默认false: 相反
index:发送指定的目录索引文件。
默认'index.html':如果请求一个目录,默认返回index.html文件
false:禁用目录索引
lastModified:
设置文件在系统中的最后修改时间到Last-Modified头部
默认true:开启
false:关闭
maxAge:设置Cache-Control标头的max-age属性,设置缓存文件的最大过期时间
如果过期就重新请求,而不是调用缓存
以毫秒为单位或字符串
redirect:当路径名是目录时,重定向到尾随“/”(这个我不太懂,有没有大佬提示的)
默认true:开启
false:关闭
setHeaders:设置响应头
function (res, path, stat) {
res.set('x-timestamp', Date.now())
}
其中
res,响应对象。
path,正在发送的文件路径。
stat,正在发送的文件的对象。