從koa-static中間件學習搭建靜態文件服務器

從koa-static中間件學習搭建靜態文件服務器

原文地址

koa-send

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-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
      }
    }
  }
相關文章
相關標籤/搜索