response-error.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. 'use strict'
  2. // const { parseHeaders } = require('../core/util')
  3. const DecoratorHandler = require('../handler/decorator-handler')
  4. const { ResponseError } = require('../core/errors')
  5. class ResponseErrorHandler extends DecoratorHandler {
  6. #statusCode
  7. #contentType
  8. #decoder
  9. #headers
  10. #body
  11. constructor (_opts, { handler }) {
  12. super(handler)
  13. }
  14. #checkContentType (contentType) {
  15. return (this.#contentType ?? '').indexOf(contentType) === 0
  16. }
  17. onRequestStart (controller, context) {
  18. this.#statusCode = 0
  19. this.#contentType = null
  20. this.#decoder = null
  21. this.#headers = null
  22. this.#body = ''
  23. return super.onRequestStart(controller, context)
  24. }
  25. onResponseStart (controller, statusCode, headers, statusMessage) {
  26. this.#statusCode = statusCode
  27. this.#headers = headers
  28. this.#contentType = headers['content-type']
  29. if (this.#statusCode < 400) {
  30. return super.onResponseStart(controller, statusCode, headers, statusMessage)
  31. }
  32. if (this.#checkContentType('application/json') || this.#checkContentType('text/plain')) {
  33. this.#decoder = new TextDecoder('utf-8')
  34. }
  35. }
  36. onResponseData (controller, chunk) {
  37. if (this.#statusCode < 400) {
  38. return super.onResponseData(controller, chunk)
  39. }
  40. this.#body += this.#decoder?.decode(chunk, { stream: true }) ?? ''
  41. }
  42. onResponseEnd (controller, trailers) {
  43. if (this.#statusCode >= 400) {
  44. this.#body += this.#decoder?.decode(undefined, { stream: false }) ?? ''
  45. if (this.#checkContentType('application/json')) {
  46. try {
  47. this.#body = JSON.parse(this.#body)
  48. } catch {
  49. // Do nothing...
  50. }
  51. }
  52. let err
  53. const stackTraceLimit = Error.stackTraceLimit
  54. Error.stackTraceLimit = 0
  55. try {
  56. err = new ResponseError('Response Error', this.#statusCode, {
  57. body: this.#body,
  58. headers: this.#headers
  59. })
  60. } finally {
  61. Error.stackTraceLimit = stackTraceLimit
  62. }
  63. super.onResponseError(controller, err)
  64. } else {
  65. super.onResponseEnd(controller, trailers)
  66. }
  67. }
  68. onResponseError (controller, err) {
  69. super.onResponseError(controller, err)
  70. }
  71. }
  72. module.exports = () => {
  73. return (dispatch) => {
  74. return function Intercept (opts, handler) {
  75. return dispatch(opts, new ResponseErrorHandler(opts, { handler }))
  76. }
  77. }
  78. }