NodeJS / Express: не соответствует [ERR_HTTP_HEADERS_SENT] - PullRequest
0 голосов
/ 17 февраля 2020

Здесь у меня есть метод POST, который вызывается довольно часто.

app.post('/return_data', async (req, res) => {
    var response, file
    console.log("request recieved: " + req.body.room)
    await readFile('Data/'+req.body.room+'.json').then((data) => {
        console.log(data)
        return res.send(data)
    }).catch((e) => {
        console.log(e)
    })
}) 

По какой-то причине ответ прерывистый. Иногда регистрируется следующая ошибка:

Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:535:11)
    at ServerResponse.header (/home/ec2-user/dc-floorplans/node_modules/express/lib/response.js:771:10)
    at ServerResponse.send (/home/ec2-user/dc-floorplans/node_modules/express/lib/response.js:194:10)
    at /home/ec2-user/dc-floorplans/app.js:127:13
    at processTicksAndRejections (internal/process/task_queues.js:97:5)
    at async /home/ec2-user/dc-floorplans/app.js:125:5 {
  code: 'ERR_HTTP_HEADERS_SENT'
}

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

Я знаю, что readFile работает, потому что данные зарегистрированы в .then(). Как может быть так, что иногда данные отправляются клиенту, а иногда он выдает ошибку, когда происходит точно такой же процесс?

Заранее спасибо.

UPDATE - FULL APP. JS:

app.set('view-engine', 'ejs');
app.use(express.urlencoded({ extended: false }))
app.use(cors())
app.use(flash())
app.use(session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false
}))
app.use(passport.initialize())
app.use(passport.session())
app.use(methodOverride('_method'))
app.use(express.static(__dirname + '/static'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

app.get('/', checkAuthenticated, (req, res) => {
    res.render('index.ejs');
});

app.get('/login', checkNotAuthenticated, function(req, res, next) {
    res.render('login.ejs');
});

app.post('/login', checkNotAuthenticated, (req, res, next) => {
        passport.authenticate('local', (err, user, info) => {
           if(err) throw err
           if(!user) return res.redirect('/login')
           req.logIn(user, (err) => {
              if(err) return next(err)
              if(info.message==process.env.DEFAULTPW) {
                  console.log("Default password detected for: " + user.email)
                  return res.redirect('/')
              }
              return res.redirect('/')

           })
  })(req, res, next)
})

app.get('/update', checkAuthenticated, (req, res, next) => {
        res.render('update.ejs')
})

app.post('/update', checkAuthenticated, async (req, res, next) => {
    if(req.body.pw1 != req.body.pw2) { res.redirect('/update') }
        if(req.body.pw2 == process.env.DEFAULTPW) { res.redirect('/update') }
        const newpw = await encrypt(req.body.pw2)
        var queryresult
        await con.query("UPDATE login SET password = \'"+newpw+"\' WHERE email = \'"+req.body.email.toLowerCase()+"\'", (err, result, fields) => {
            if (err) {
                console.log(err)
                return res.redirect('/update')
            };
                console.log(result)
        queryresult = result
                if(result.changedRows == 0) {
                    return res.redirect('/update')
                }

        })
        return res.redirect('/')
    });

app.post('/get_new_data', async (req, res)  => {

        console.log("New Data:")
    await pollLM(req.body.room).then((data) => {
        console.log(data)
        return res.send(data)
    }).catch((e) => {
        console.log(e)
    })
})

async function pollLM(room) {
    return new Promise((resolve, reject) => {
        const getData = pySpawn('python3.7', ['getData.py', room])
        getData.stdout.on('data', (data) => {
        resolve(data)
        })
    })
}

app.post('/return_data', async (req, res) => {

    console.log("request recieved: " + req.body.room)
    await readFile('Data/'+req.body.room+'.json').then((data) => {
        console.log(data)
        return res.send(data)
    }).catch((e) => {
        console.log(e)
    })
})

async function readFile(path) {
    return new Promise((resolve, reject) => {
        fs.readFile(path, (err, data) => {
            if (err) reject(err);
            console.log(typeof(data))
            resolve(data)
        })
    })
}

app.post('/update_reload_time', (req, res) => {
    console.log("reload time updated to: " + req.body.time)
    fs.writeFile('Data/delay.json', JSON.stringify(req.body), () => {
        console.log("delay updated to: " + req.body.time)
    })
})

app.get('/reload_time', async (req, res) => {

    await readFile('Data/delay.json').then((data) => {
        console.log(data)
        return res.send(data)
    }).catch((e) => {
        console.log(e)
    })
})

app.delete('/logout', (req, res) => {
    req.logOut()
    res.redirect('/login')
})

// Page routing...

function checkAuthenticated(req, res, next) {
    if(req.isAuthenticated()) {
        return next()
    }
    res.redirect('/login')
}

function checkNotAuthenticated(req, res, next) {
    if(req.isAuthenticated()) {
        return res.redirect('/')
    }
    next()
}

function encrypt(text) {
    const key = crypto.scryptSync(process.env.CRYPTOPW, process.env.SALT, 24)
        const cipher = crypto.createCipher('aes-192-cbc', key)

        let encrypted = ''
        cipher.on('readable', () => {
            let chunk
            while(null != (chunk = cipher.read())) {
                encrypted += chunk.toString('hex')
            }
        })

        cipher.write(text)
        cipher.end()
        return encrypted
}

function decrypt(text) {
    const key = crypto.scryptSync(process.env.CRYPTOPW, process.env.SALT, 24)
      const decipher = crypto.createDecipher('aes-192-cbc', key)

      let decrypted = '';
      decipher.on('readable', () => {
        while(null !== (chunk = decipher.read())) {
          decrypted += chunk.toString('utf8')
        }
      })

      const encrypted = text
      decipher.write(encrypted, 'hex')
      decipher.end()
      return decrypted
}

1 Ответ

0 голосов
/ 18 февраля 2020

Все, что вам нужно искать, это когда вы отвечаете дважды на один и тот же вызов.

Например:

app.post('test', (req,res)=>{
 res.send('1')
 res.json('{1:2}')
})

всегда будет возвращать эту ошибку, потому что вы отвечаете дважды.

Вы должны исследовать свои маршруты один за другим, я бы начал здесь:

app.post('/update', checkAuthenticated, async (req, res, next) => {
if(req.body.pw1 != req.body.pw2) { res.redirect('/update') }
    if(req.body.pw2 == process.env.DEFAULTPW) { res.redirect('/update') }
    const newpw = await encrypt(req.body.pw2)
    var queryresult
    await con.query("UPDATE login SET password = \'"+newpw+"\' WHERE email = \'"+req.body.email.toLowerCase()+"\'", (err, result, fields) => {
        if (err) {
            console.log(err)
            return res.redirect('/update')
        };
            console.log(result)
    queryresult = result
            if(result.changedRows == 0) {
                return res.redirect('/update')
            }

    })
    return res.redirect('/')
});

Вы вызываете res.redirect явно и при условии. Проверяли ли вы оба условия одновременно? Я предполагаю, что здесь есть одно слабое место.

И я бы проверил это

    app.post('/login', checkNotAuthenticated, (req, res, next) => {
        passport.authenticate('local', (err, user, info) => {
           if(err) throw err
           if(!user) return res.redirect('/login')
           req.logIn(user, (err) => {
              if(err) return next(err)
              if(info.message==process.env.DEFAULTPW) {
                  console.log("Default password detected for: " + user.email)
                  return res.redirect('/')
              }
              return res.redirect('/')

           })
  })(req, res, next)
})

Снова там потенциально выполняются два условия. Проверь их. Другие части выглядят хорошо для меня.

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