Не удается установить заголовки после их отправки клиенту, когда я пытаюсь сделать запрос на обновление - PullRequest
0 голосов
/ 11 апреля 2020

Я пытаюсь создать CRUD. У меня создано ОБНОВЛЕНИЕ, но когда я пытаюсь запросить у почтальона, я получаю следующую ошибку:

Ошибка [ERR_HTTP_HEADERS_SENT]: Невозможно установить заголовки после того, как они отправлены клиенту на ServerResponse.setHeader ( _http_outgoing. js: 526: 11) в ServerResponse.header (E: \ freebooks-core-api \ node_modules \ express \ lib \ response. js: 771: 10) в ServerResponse.send (E: \ freebooks- core-api \ node_modules \ express \ lib \ response. js: 170: 12) в ServerResponse. json (E: \ freebooks-core-api \ node_modules \ express \ lib \ response. js: 267: 15) в ServerResponse.send (E: \ freebooks-core-api \ node_modules \ express \ lib \ response. js: 158: 21) в Object.exports.success (E: \ freebooks-core-api \ network \ ответ. js: 3: 6) в E: \ freebooks-core-api \ components \ book \ network. js: 32: 18 в processTicksAndRejected (внутренний / process / task_queues. js: 97: 5) {code: 'ERR_HTTP_HEADERS_SENT'} (узел: 2844) UnhandledPromiseRejectionWarning: Ошибка [ERR_HTTP_HEADERS_SENT]: невозможно установить заголовки после их отправки t для клиента в ServerResponse.setHeader (_http_outgoing. js: 526: 11) в ServerResponse.header (E: \ freebooks-core-api \ node_modules \ express \ lib \ response. js: 771: 10) в ServerResponse.send (E: \ freebooks-core-api \ node_modules \ express \ lib \ response. js: 170: 12) в ServerResponse. json (E: \ freebooks-core-api \ node_modules \ express \ lib \ response. js: 267: 15) в ServerResponse.send (E: \ freebooks-core-api \ node_modules \ express \ lib \ response. js: 158: 21) в Object.exports.error (E: \ freebooks-core-api \ network \ response. js: 12: 6) в E: \ freebooks-core-api \ components \ book \ network. js: 34: 16 в processTicksAndRejected (внутренняя / process / task_queues . js: 97: 5) (узел: 2844) UnhandledPromiseRejectionWarning: необработанное отклонение обещания. Эта ошибка возникла либо из-за того, что внутри asyn c -функции не было блока catch, либо из-за отклонения обещания, которое не было обработано с помощью .catch (). Чтобы завершить процесс узла при отклонении необработанного обещания, используйте флаг CLI --unhandled-rejections=strict (см. https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (идентификатор отклонения: 1) (узел: 2844) [DEP0018] Предупреждение об устаревании: отклонения необработанного обещания устарели. В будущем отклонения обещаний, которые не обрабатываются, завершат процесс Node.js с ненулевым кодом завершения.

Как я читал в сообщении об ошибке, это происходит из следующих файлов:

ответ. js в моей сетевой папке

exports.success = function (req, res, data, status) {
  res.status(status || 200)
    .send({
      error: '',
      data
    })
}

exports.error = function (req, res, error, status, log) {
  console.log(log)
  res.status(status || 500)
    .send({
      error,
      data: ''
    })
}

и сеть. js в моей папке с книгами (компонентами):

const router = require('express').Router()
const response = require('../../network/response')
const controller = require('./controller')

router.get('/', function (req, res) {
    controller.getBooks()
        .then( data => {
            response.success(req, res, data, 200)
        })
        .catch( err => {
            response.error(req, res, 'Unexpected Error', 500, err)
        })
})

router.post('/', function (req, res) {
  const book = req.body
  console.log(book)
  controller.addBook(book).then( data => {
    response.success(req, res, book, 201)
  })
    .catch(err => {
      response.error(req, res, 'Internal error', 500, err)
    })
})

router.patch('/:id', function(req, res) {
  const { id } = req.params
  console.log(id)
  const book = req.body
  controller.updateBook(id, book)
    .then( data => {
        response.success(req, res, data, 200)
    }).catch( err => {
      response.error(req, res, 'Internal error', 500, err)
    }) 
  res.send('Ok')
})

module.exports = router

но так как я звоню на контроллер и в этой строке запускается ошибка, это код:

const store = require('./store')

function getBooks () {
  return new Promise((resolve, reject) => {

    resolve(store.list())
  })
}

function addBook (book) {
  return new Promise((resolve, reject) => {
    if (!book) {
      reject('I reject')
      return false
    } else {

      resolve(book)
      store.add(book)
    }
  })
}

 function updateBook (id, book) {
  return new Promise( async (resolve, reject) => {
      if (!id || !book) {
          reject('Invalid data')
          return false
      } else {
        const result = await store.update(id, book)
        resolve(result)
      }

  })
}

function deleteBook (id) {
  return new Promise( async (resolve, reject) => {
      if (!id) {
          reject('Invalid data')
          return false
      } else {
        const result = await store.update(id)
        resolve(result)
      }

  })
}

module.exports = {
  addBook,
  getBooks,
  updateBook,
  deleteBook
}

наконец store

const db = require('mongoose')
const Model = require('./model')

db.Promise = global.Promise
db.connect(`mongodb+srv://fewtwtwfwe:efwefwecwecw@ferwrtervsefwg/test?retryWrites=true&w=majority`, {
    useNewUrlParser: true,
    useUnifiedTopology: true
}).then( () => {
    console.log(`Database connected`)
}).catch( err => {
    console.error(err)
})

function addBook(book) {
    const myBook = new Model(book)
    myBook.save()
}

async function getBooks() {
   const books =  await Model.find()
   return books
}

async function updateBook(id, book) {
    const foundBook = await Model.findOne({
        '_id':id
    })
    foundBook.book = book
    const newBook = await foundBook.save()
    return newBook
}

async function deleteBook(id) {
    const foundBook = await Model.findOne({
        '_id':id
    })
}


module.exports = {
    add: addBook,
    list: getBooks,
    update: updateBook,
    delete: deleteBook,
}

Я изменил данные подключения к базе данных, потому что я уверен, что ошибка там не l ie, я сделал другие запросы и, видимо, все в порядке. Есть идеи?

1 Ответ

1 голос
/ 11 апреля 2020

Вы можете отправить только один ответ на каждый входящий запрос. Это конкретное сообщение об ошибке говорит вам, что ваш код пытается отправить два запроса. Чаще всего это происходит из-за неправильной последовательности кода с асинхронными функциями. Это похоже на случай с этим маршрутом:

router.patch('/:id', function(req, res) {
  const { id } = req.params
  console.log(id)
  const book = req.body
  controller.updateBook(id, book)
    .then( data => {
        response.success(req, res, data, 200)
    }).catch( err => {
      response.error(req, res, 'Internal error', 500, err)
    }) 
  res.send('Ok')
})

Сначала он выполняет:

controller.updateBook()

, а затем во время выполнения этой асинхронной операции он выполняет:

res.send('Ok');

Затем, спустя некоторое время, updateBook() завершается, и он вызывает обработчик .then() или .catch(), и вы затем пытаетесь отправить другой ответ на тот же запрос.

Похоже, что вы следует просто полностью удалить res.send('Ok'), поскольку вы хотите, чтобы ответ отправлялся в соответствии со статусом updateBook() в обработчике .then() или .catch().


В совершенно отдельном topi c, это немного против паттерна - оборачивать функцию возврата обещания в другое обещание, как вы делаете в updateBook(). Я бы посоветовал вам изменить это:

function updateBook (id, book) {
  return new Promise( async (resolve, reject) => {
      if (!id || !book) {
          reject('Invalid data')
          return false
      } else {
        const result = await store.update(id, book)
        resolve(result)
      }

  })
}

на это:

function updateBook (id, book) {
    if (!id || !book) {
        return Promise.reject('Invalid data');
    } else {
        return store.update(id, book);
    }
}

К вашему сведению, причина в том, что это анти-шаблон, потому что это и ненужный код, и люди часто делают ошибки в обработка ошибок, которая именно то, что вы сделали. Если store.update() отклонено, у вас не было try/catch около await, чтобы поймать эту ошибку, чтобы она была потеряна и ваше обещание никогда не было бы решено или отклонено.

Вы должны изменить все аналогично структурированные функции, чтобы исправить это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...