Static file serving middleware
koa-static中有說明它只是koa-send的一個包裝html
const send = require('koa-send'); app.use(async (ctx) => { await send(ctx, ctx.path, { root: __dirname + '/public' }); })
查看koa-send的源碼能夠發現,它作的工做是根據傳入的path查找文件是否存在,若是存在就建立一個流,不存在就拋出錯誤。 git
send函數能夠傳入第三個參數github
maxage
Browser cache max-age in milliseconds. (defaults to 0
)immutable
Tell the browser the resource is immutable and can be cached indefinitely. (defaults to false
)hidden
Allow transfer of hidden files. (defaults to false
)root
Root directory to restrict file access.index
Name of the index file to serve automatically when visiting the root location. (defaults to none)gzip
Try to serve the gzipped version of a file automatically when gzip
is supported by a client and if the requested file with .gz
extension exists. (defaults to true
).brotli
Try to serve the brotli version of a file automatically when brotli
is supported by a client and if the requested file with .br
extension exists. (defaults to true
).format
If not false
(defaults to true
), format the path to serve static file servers and not require a trailing slash for directories, so that you can do both /directory
and /directory/
.setHeaders
Function to set custom headers on response.extensions
Try to match extensions from passed array to search for file when no extension is sufficed in URL. First found is served. (defaults to false
)能夠看一下index的做用,事實上當咱們在地址欄輸入json
http://www.aaa.com/ 或者 http://www.aaa.com/index.html
能夠發現效果是同樣的,緣由就是配置了index選項,服務端首先檢查你的path是否以 '/' 結尾,假如你配置了index選項且以 '/' 結尾,那麼服務端會自動將你的path和index選項拼接,以下:服務器
const trailingSlash = path[path.length - 1] === '/' ... if (index && trailingSlash) path += index
再看一下format的做用,其實咱們常常在地址欄輸入的是app
http://www.aaa.com 而不是 http://www.aaa.com/
但他們的效果也是同樣的,緣由就是配置了format,通過resolve以後的path返回的是一個絕對路徑,它是其中一種狀態(文件或者文件夾),若是是文件夾,且設置了format(默認爲true)和index,那麼就自動添加indexkoa
stats = await fs.stat(path) // Format the path to serve static file servers // and not require a trailing slash for directories, // so that you can do both `/directory` and `/directory/` if (stats.isDirectory()) { if (format && index) { path += '/' + index stats = await fs.stat(path) } else { return } }
extensions的做用好像很少見,好比你的a文件夾async
| - a | - demo.txt | - demo.json | - demo.html
假如你設置了extensions(假設爲['json', 'txt']),那麼你在地址欄輸入函數
http://www.aaa.com/a/demo 事實上等同於 http://www.aaa.com/a/demo.json
服務端會首先判斷你是否設置了extensions且path不以 '.**' 結尾學習
if (extensions && !/\..*$/.exec(path)) { const list = [].concat(extensions) for (let i = 0; i < list.length; i++) { let ext = list[i] if (typeof ext !== 'string') { throw new TypeError('option extensions must be array of strings or false') } // ['.js'] 或者 ['js'] 都可以 if (!/^\./.exec(ext)) ext = '.' + ext if (await fs.exists(path + ext)) { path = path + ext break } } }
而後按照extensions的順序依次查找拼接的path是否存在,存在即中止查找
koa-static的只是給koa-send包了一層,koa-send的第二個參數path是ctx.path
koa-static有個defer選項
defer
If true, serves after return next(), allowing any downstream middleware to respond first.if (!opts.defer) { return async function serve (ctx, next) { let done = false if (ctx.method === 'HEAD' || ctx.method === 'GET') { try { // koa-send 輸入的path不存在時拋錯(404或者500) done = await send(ctx, ctx.path, opts) } catch (err) { // 若是錯誤碼是404說明請求的不是靜態文件 if (err.status !== 404) { throw err } } } // 請求不是靜態文件 繼續執行下面的邏輯 if (!done) { await next() } } } return async function serve (ctx, next) { await next() // 假如請求方法不是get 必然不是訪問靜態資源 if (ctx.method !== 'HEAD' && ctx.method !== 'GET') return // 說明對請求已經作了響應 if (ctx.body != null || ctx.status !== 404) return // eslint-disable-line try { await send(ctx, ctx.path, opts) } catch (err) { if (err.status !== 404) { throw err } } }