美文网首页
koa静态文件处理

koa静态文件处理

作者: 马贞晓 | 来源:发表于2018-11-05 11:14 被阅读0次

koa使用koa-staitc来处理静态文件

其核心使用koa-send组件来完成,对齐文件进行解析,它对文件进行了几项处理
1、对组件root目录,和请求路径进行合并,并对返回文件头进行处理,主要针对.br 和.gz

app.use(static(你要制定的静态文件根目录)) 。
所以你要请求的路径中不能带入跟目录相关字段,直接请求文件即可,请求早于其他使用router包请求处理,所以尽量不要和后面的非静态路径请求冲突。

以下最主要就一句ctx.body = fs.createReadStream(path),加上文件头就是核心。

/**
 * Module dependencies.
 */

const debug = require('debug')('koa-send')
const resolvePath = require('resolve-path')
const createError = require('http-errors')
const assert = require('assert')
const fs = require('mz/fs')

const {
  normalize,
  basename,
  extname,
  resolve,
  parse,
  sep
} = require('path')

/**
 * Expose `send()`.
 */

module.exports = send

/**
 * Send file at `path` with the
 * given `options` to the koa `ctx`.
 *
 * @param {Context} ctx
 * @param {String} path
 * @param {Object} [opts]
 * @return {Function}
 * @api public
 */

async function send (ctx, path, opts = {}) {
  assert(ctx, 'koa context required')
  assert(path, 'pathname required')

  // options
  debug('send "%s" %j', path, opts)
  const root = opts.root ? normalize(resolve(opts.root)) : ''
  const trailingSlash = path[path.length - 1] === '/'
  path = path.substr(parse(path).root.length)
  const index = opts.index
  const maxage = opts.maxage || opts.maxAge || 0
  const immutable = opts.immutable || false
  const hidden = opts.hidden || false
  const format = opts.format !== false
  const extensions = Array.isArray(opts.extensions) ? opts.extensions : false
  const brotli = opts.brotli !== false
  const gzip = opts.gzip !== false
  const setHeaders = opts.setHeaders

  if (setHeaders && typeof setHeaders !== 'function') {
    throw new TypeError('option setHeaders must be function')
  }

  // normalize path
  path = decode(path)

  if (path === -1) return ctx.throw(400, 'failed to decode')

  // index file support
  if (index && trailingSlash) path += index

  path = resolvePath(root, path)

  // hidden file support, ignore
  if (!hidden && isHidden(root, path)) return

  let encodingExt = ''
  // serve brotli file when possible otherwise gzipped file when possible
  if (ctx.acceptsEncodings('br', 'identity') === 'br' && brotli && (await fs.exists(path + '.br'))) {
    path = path + '.br'
    ctx.set('Content-Encoding', 'br')
    ctx.res.removeHeader('Content-Length')
    encodingExt = '.br'
  } else if (ctx.acceptsEncodings('gzip', 'identity') === 'gzip' && gzip && (await fs.exists(path + '.gz'))) {
    path = path + '.gz'
    ctx.set('Content-Encoding', 'gzip')
    ctx.res.removeHeader('Content-Length')
    encodingExt = '.gz'
  }

  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')
      }
      if (!/^\./.exec(ext)) ext = '.' + ext
      if (await fs.exists(path + ext)) {
        path = path + ext
        break
      }
    }
  }

  // stat
  let stats
  try {
    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
      }
    }
  } catch (err) {
    const notfound = ['ENOENT', 'ENAMETOOLONG', 'ENOTDIR']
    if (notfound.includes(err.code)) {
      throw createError(404, err)
    }
    err.status = 500
    throw err
  }

  if (setHeaders) setHeaders(ctx.res, path, stats)

  // stream
  ctx.set('Content-Length', stats.size)
  if (!ctx.response.get('Last-Modified')) ctx.set('Last-Modified', stats.mtime.toUTCString())
  if (!ctx.response.get('Cache-Control')) {
    const directives = ['max-age=' + (maxage / 1000 | 0)]
    if (immutable) {
      directives.push('immutable')
    }
    ctx.set('Cache-Control', directives.join(','))
  }
  if (!ctx.type) ctx.type = type(path, encodingExt)
  ctx.body = fs.createReadStream(path)

  return path
}

/**
 * Check if it's hidden.
 */

function isHidden (root, path) {
  path = path.substr(root.length).split(sep)
  for (let i = 0; i < path.length; i++) {
    if (path[i][0] === '.') return true
  }
  return false
}

/**
 * File type.
 */

function type (file, ext) {
  return ext !== '' ? extname(basename(file, ext)) : extname(file)
}

/**
 * Decode `path`.
 */

function decode (path) {
  try {
    return decodeURIComponent(path)
  } catch (err) {
    return -1
  }
}

相关文章

  • koa静态文件处理

    koa使用koa-staitc来处理静态文件 其核心使用koa-send组件来完成,对齐文件进行解析,它对文件进行...

  • koa静态文件处理

    如何使用: 这里利用koa-static中间件,就可以进行处理

  • Koa-static-cache处理静态文件

    koa-static-cache插件:处理服务器静态文件,自带缓存机制。用法:server.use(staticC...

  • 8KOA 静态文件

    静态文件 使用 koa-static 中间件实现静态文件访问 安装中间件 使用中间件 使用 koa-mount 自...

  • Koa项目总结四:Koa静态资源的配置

    使用koa-static中间件来处理Koa项目中的静态资源。 1.1 koa-static安装: 1.2 koa-...

  • Koa实战-鉴权

    课程目标 @掌握Koa基本用法 @理解Koa设计思路 @路由 @静态文件服务 @模板引擎 koa 概述:ko...

  • koa2入门系列 Part 4

    koa静态文件配置 上一节讲述了在koa中的模版渲染,也就是html文件在koa中的应用,但作为前端的渲染文件,光...

  • koa2静态文件

    这篇主要介绍koa2处理静态文件的中间件 用到的版本: 项目的结构: 大家可以往static文件夹里面添加点东西 ...

  • koa-static与koa-router

    koa-static会拦截请求路径进行处理 如果不是静态文件将会返回http404,两个中间件同时使用时应该先执行...

  • 手写一个 Koa --- Koa 原理学习

    一个学习 Koa 源码的例子 学习目标:原生 node 封装中间件路由静态文件服务(未完成待续) Koa 原理 一...

网友评论

      本文标题:koa静态文件处理

      本文链接:https://www.haomeiwen.com/subject/vynjxqtx.html