Http-errors is a basic library widely used by the KOA and Express communities to handle HTTP errors.

For example, koa-router is used:

notImplementedThrowable = new HttpError.NotImplemented();

notAllowedThrowable = new HttpError.MethodNotAllowed();

Copy the code

Other use here we suggest that you see the document: github.com/jshttp/http…

The source code

statuses

A statuses library is used in HTTP-Errors, which is a tool library for handling HTTP status.

For example, get all HTTP status codes through status.codes.

[
  100.101.102.103.200.201.202.203.204.205.206.207.208.226.300.301.302.303.304.305.306.307.308.400.401.402.403.404.405.406.407.408.409.410.411.412.413.414.415.416.417.418.421.422.423.424.425.426.428.429.431.451.500.501.502.503.504.505.506.507.508.509.510.511
]
Copy the code

For example, statuses[code] get the corresponding HTTP code MSG according to the code.

Continue 100
Switching Protocols 101
Processing 102
Early Hints 103
OK 200
Created 201
Accepted 202
Non-Authoritative Information 203
No Content 204
Reset Content 205
Partial Content 206
Multi-Status 207
Already Reported 208
IM Used 226
Multiple Choices 300
Moved Permanently 301
Found 302
See Other 303
Not Modified 304
Use Proxy 305
(Unused) 306
Temporary Redirect 307
Permanent Redirect 308
Bad Request 400
Unauthorized 401
Payment Required 402
Forbidden 403
Not Found 404
Method Not Allowed 405
Not Acceptable 406
Proxy Authentication Required 407
Request Timeout 408
Conflict 409
Gone 410
Length Required 411
Precondition Failed 412
Payload Too Large 413
URI Too Long 414
Unsupported Media Type 415
Range Not Satisfiable 416
Expectation Failed 417
I'm a teapot 418
Misdirected Request 421
Unprocessable Entity 422
Locked 423
Failed Dependency 424
Unordered Collection 425
Upgrade Required 426
Precondition Required 428
Too Many Requests 429
Request Header Fields Too Large 431
Unavailable For Legal Reasons 451
Internal Server Error 500
Not Implemented 501
Bad Gateway 502
Service Unavailable 503
Gateway Timeout 504
HTTP Version Not Supported 505
Variant Also Negotiates 506
Insufficient Storage 507
Loop Detected 508
Bandwidth Limit Exceeded 509
Not Extended 510
Network Authentication Required 511
Copy the code

inherits

Inherits is an early implementation by Isaacs of a simple JS inheritance that is compatible with browser and Node environments.

try {
  // The node environment uses util.inherits
  var util = require('util');
  /* istanbul ignore next */
  if (typeofutil.inherits ! = ='function') throw ' ';
  module.exports = util.inherits;
} catch (e) {
  // The browser environment implements one itself
  /* istanbul ignore next */
  module.exports = require('./inherits_browser.js');
}
Copy the code

The corresponding inherits_browser.js is available here as well.

if (typeof Object.create === 'function') {
  // If Object. Create is supported, we simply implement an inherits by referring to node.js 'util' module
  module.exports = function inherits(ctor, superCtor) {
    if (superCtor) {
      // Write the superclass constructor into the subclass's.super_ property, which can be used to call the superclass constructor.
      ctor.super_ = superCtor
      // Prototype inheritance
      ctor.prototype = Object.create(superCtor.prototype, {
        constructor: {
          value: ctor,
          enumerable: false.writable: true.configurable: true}}}}; }else {
  // old school shim for old browsers
  module.exports = function inherits(ctor, superCtor) {
    if (superCtor) {
      ctor.super_ = superCtor
      var TempCtor = function () {}
      TempCtor.prototype = superCtor.prototype
      ctor.prototype = new TempCtor()
      ctor.prototype.constructor = ctor
    }
  }
}
Copy the code

setprototypeof

Setprototypeof is a library for Polyfill for Object. setPrototypeof, which is cross-platform and compatible with IE8.

'use strict'
/* eslint no-proto: 0 */
module.exports = Object.setPrototypeOf || ({ __proto__: []}instanceof Array ? setProtoOf : mixinProperties)

function setProtoOf (obj, proto) {
  obj.__proto__ = proto
  return obj
}

function mixinProperties (obj, proto) {
  for (var prop in proto) {
    if (!Object.prototype.hasOwnProperty.call(obj, prop)) {
      obj[prop] = proto[prop]
    }
  }
  return obj
}
Copy the code

http-errors

/ *! * http-errors * Copyright(c) 2014 Jonathan Ong * Copyright(c) 2016 Douglas Christopher Wilson * MIT Licensed */

'use strict'

/**
 * Module dependencies.
 * @private* /

var deprecate = require('depd') ('http-errors')
// Polyfill for Object.setPrototypeOf
var setPrototypeOf = require('setprototypeof')
var statuses = require('statuses')
var inherits = require('inherits')
var toIdentifier = require('toidentifier')

/**
 * Module exports.
 * @public* /

module.exports = createError
module.exports.HttpError = createHttpErrorConstructor() // Generate an abstract base class
module.exports.isHttpError = createIsHttpErrorFunction(module.exports.HttpError)

// Populate exports for all constructors
// ucMS. Codes: Array of status codes
/ / /
// 100, 101, 102, 103,
// 200, 201, 202, 203, 204, 205, 206, 207, 208, 226,
// 300, 301, 302, 303, 304, 305, 306, 307, 308,
// 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 413, 414, 415, 416, 417, 418, 421, 422, 423, 424, 425, 426, 428, 429, 431, 451, 500, 501,
// 502, 503, 504, 505, 506, 507, 508, 509, 510, 511
// ]

// Execute by default
populateConstructorExports(module.exports, statuses.codes, module.exports.HttpError)

/** * 4xx => 400, 5xx => 500, that is, to obtain the code category *@private* /

function codeClass (status) {
  return Number(String(status).charAt(0) + '00')}/** * Directly generates the corresponding HTTP Error instance * based on the caller's argument@returns {Error}
 * @public* /

function createError () {
  // so much arity going on ~_~
  var err
  var msg
  // Default status code 500
  var status = 500
  var props = {}
  // Pass through the parameters, handle err, MSG, status, props
  for (var i = 0; i < arguments.length; i++) {
    var arg = arguments[i]
    if (arg instanceof Error) {
      // If it is an Error instance, store err and status
      err = arg
      // status: status code, where status may be a string
      status = err.status || err.statusCode || status
      continue
    }
    switch (typeof arg) {
      case 'string':
        // If it is a string, consider it error MSG
        msg = arg
        break
      case 'number':
        // If it is a number, consider it a status code
        status = arg
        if(i ! = =0) {
          CreateError ([status], [error], [properties])
          deprecate('non-first-argument status code; replace with createError(' + arg + ',...). ')}break
      case 'object':
        // Customize properties props
        props = arg
        break}}// Prompt => Valid status code range
  if (typeof status === 'number' && (status < 400 || status >= 600)) {
    deprecate('non-error status code; use only 4xx or 5xx status codes')}// The invalid status pocket is 500
  if (typeofstatus ! = ='number'| | (! statuses[status] && (status <400 || status >= 600))) {
    status = 500
  }

  / / populateConstructorExports () is executed by default
  // Find the corresponding exception constructor according to status
  var HttpError = createError[status] || createError[codeClass(status)]

  if(! err) {// No err constructs an exception example from HttpError
    err = HttpError
      ? new HttpError(msg)
      : new Error(msg || statuses[status])
    Remember to add createError, and all stack frames above createError, including itself, will be generated as a stack trace
    Error.captureStackTrace(err, createError)
  }

  if(! HttpError || ! (errinstanceofHttpError) || err.status ! == status) {// Err is passed in from the business definition
    // add properties to generic error
    Expose property: can be used to indicate whether the message should be sent to the client, false if the status is > = 500
    err.expose = status < 500
    err.status = err.statusCode = status
  }

  // Mount the customized business properties to ERR
  for (var key in props) {
    // Remove blacklist attributes
    if(key ! = ='status'&& key ! = ='statusCode') {
      err[key] = props[key]
    }
  }

  return err
}

/** * Create HTTP error abstract Base class. * Emulates an HTTP abstract base class as a base class for other derived classes *@private* /

function createHttpErrorConstructor () {
  // Abstract classes cannot be instantiated directly
  function HttpError () {
    throw new TypeError('cannot construct abstract class')}/ / Error
  inherits(HttpError, Error)

  return HttpError
}

/** * Generate a client exception constructor 4xx based on the HttpError base class. *@private* /

function createClientErrorConstructor (HttpError, name, code) {
  / / stitching className
  var className = toClassName(name)

  function ClientError (message) {
    // Get error message
    varmsg = message ! =null ? message : statuses[code]
    / / generated the Error
    var err = new Error(msg)

    // Capture a stack trace to the construction Point Generates the. Stack error stack attribute on err
    http://nodejs.cn/api/errors.html#errors_error_capturestacktrace_targetobject_constructoropt / / specific see API
    Error.captureStackTrace(err, ClientError)

    // adjust the [[Prototype]] set the Prototype
    setPrototypeOf(err, ClientError.prototype)

    // Redefine error message
    Object.defineProperty(err, 'message', {
      enumerable: true.configurable: true.value: msg,
      writable: true
    })

    // Redefine error name
    Object.defineProperty(err, 'name', {
      enumerable: false.configurable: true.value: className,
      writable: true
    })

    return err
  }

  inherits(ClientError, HttpError)
  // Because we all use a common ClientError function and use inherits as an inherits method, we need to define our own func.name
  nameFunc(ClientError, className)

  ClientError.prototype.status = code
  ClientError.prototype.statusCode = code
  ClientError.prototype.expose = true

  return ClientError
}

/** * Create function to test is a value is an HttpError@private* /

function createIsHttpErrorFunction (HttpError) {
  return function isHttpError (val) {
    if(! val ||typeofval ! = ='object') {
      return false
    }

    // Duck type duck type
    if (val instanceof HttpError) {
      return true
    }

    // Meet the custom error notation
    return val instanceof Error &&
      typeof val.expose === 'boolean' &&
      typeof val.statusCode === 'number' && val.status === val.statusCode
  }
}

/** * Generate a server-side exception constructor 5xx based on the HttpError base class. *@private* /

function createServerErrorConstructor (HttpError, name, code) {
  var className = toClassName(name)

  function ServerError (message) {
    // create the error object
    varmsg = message ! =null ? message : statuses[code]
    var err = new Error(msg)

    // capture a stack trace to the construction point
    Error.captureStackTrace(err, ServerError)

    // adjust the [[Prototype]]
    setPrototypeOf(err, ServerError.prototype)

    // redefine the error message
    Object.defineProperty(err, 'message', {
      enumerable: true.configurable: true.value: msg,
      writable: true
    })

    // redefine the error name
    Object.defineProperty(err, 'name', {
      enumerable: false.configurable: true.value: className,
      writable: true
    })

    return err
  }

  inherits(ServerError, HttpError)
  nameFunc(ServerError, className)

  ServerError.prototype.status = code
  ServerError.prototype.statusCode = code
  ServerError.prototype.expose = false

  return ServerError
}

/** * if possible, set function. name *@private* /

function nameFunc (func, name) {
  var desc = Object.getOwnPropertyDescriptor(func, 'name')

  if (desc && desc.configurable) {
    // Modifiable object.defineProperty
    desc.value = name
    Object.defineProperty(func, 'name', desc)
  }
}

/** * Populate the exports object with constructors for every error class@private* /

function populateConstructorExports (exports, codes, HttpError) {
  / / traverse codes
  codes.forEach(function forEachCode (code) {
    var CodeError
    // statuses[code]: Returns the corresponding HTTP status message according to the given status code, for example, 205 => Reset Content
    // toIdentifier: Converts a string to a valid identifier such as ResetContent => ResetContent
    var name = toIdentifier(statuses[code])
    switch (codeClass(code)) {
      // Handle 4xx, 5xx, generate different client exception, server exception constructor according to name, code
      case 400:
        CodeError = createClientErrorConstructor(HttpError, name, code)
        break
      case 500:
        CodeError = createServerErrorConstructor(HttpError, name, code)
        break
    }

    if (CodeError) {
      // export the constructor
      // Expose the constructor,
      // var createError = require('./source')
      // var PreconditionFailed = createError['412'] // You can load the corresponding exception constructor with [code]
      // console.log(new PreconditionFailed('xyz'))
      // var NotExtendedError = createError. notexbobgendered // Let it be told by [name]
      // console.log(new NotExtendedError('NotExtendedError'))
      exports[code] = CodeError
      exports[name] = CodeError
    }
  })

  // backwards-compatibility
  exports["I'mateapot"] = deprecate.function(exports.ImATeapot,
    '"I\'mateapot"; use "ImATeapot" instead')}/**
 * Get a class name from a name identifier.
 * @private* /

function toClassName (name) {
  // InternalServerError is similar to name ending with Error
  return name.substr(-5)! = ='Error'
    ? name + 'Error'
    : name
}
Copy the code

The code is still interesting, you can look at it.

Well, that’s all for today. See you next time.

Ps: If you are also interested in Node, please follow my official account: XYZ Programming Diary.