错误:发送HTTP节点服务器的标头后,无法设置标头

时间:2018-06-19 20:21:43

标签: javascript node.js http

我正在尝试根据url值将多个值传递给服务器。

我的结果值如下所示

[ { url: 'account/41',

    status: '200',

    headers:

     [ 'content-type = application/json,',

       'content-type = application/text' ],

    body: [ '{ name: XYZ }' ] },

  { url: 'account/43',

    status: '201',

    headers: [ 'content-type = application/xml']

    body: [ '{ name : ZYX }' ] } ]

在这里,我正在尝试为上述多个值创建服务器请求/响应。我使用forEach循环进行迭代,例如url = account / 41,则body将返回['{name:XYZ}']};如果url = account / 43,则body将返回['{name:ZYX}']。但这只是获取结果值的第一个元素,并给我以下错误:

UnhandledPromiseRejectionWarning: Error: Can't set headers after they are sent.

我想念的东西,但不确定吗?如何通过正确的输出一对一传递值。

const http = require('http')

const parse = require('./Parse.js')



// create a server object:

let server = http.createServer(function(request, response) {

    parse.allFiles().then( results => {

        results.forEach(element => {

            if (element.url.includes(request.url) ) {

            let headerSplit = ( element.headers + '' ).split('=')

            let headername = headerSplit[0]

            let headerVal = headerSplit[1]

            response.setHeader( headername, headerVal )

            response.write( JSON.stringify( element.body ) )

            response.statuscode = parseInt( element.status )

            response.end()

        } else {

            response.writeHead(404, {'Content-Type': 'text/html'})

            response.end('No Page Found')

        }

        })

    })

})



const port = process.env.PORT || 8080



server.listen(port, function() {

// eslint-disable-next-line no-console

console.log('Listening on port ' + port)

})

我有多个文件,这些文件带有自己的URL,STATUS,HEADERS和BODY。在单个数组中解析了这些值(使用Parse函数)之后,我进入了名为result的变量。

[{"url":"account/41","status":"200","headers":["content-type = application/json,"],"body":["{ name: xyz}"]},
{"url":"account/43","status":"201","headers":["content-type = application/xml"],"body":["{ name : zyx}"]}]

如果对结果进行迭代,则会得到类似{“ url”:“ account / 41”,“ status”:“ 200”,“ headers”:[“ content-type = application / json”]的元素, “ body”:[“ {name:xyz}”]},如果您将网址传递给服务器,例如localhost:8080 / account / 41,它将作为响应返回[“ {name:zyx}”]}]]身体。

1 个答案:

答案 0 :(得分:3)

您在response.end()循环中有一个.forEach()。这意味着您要多次调用它。您只能为每个请求调用一次,因为当您调用它时,将写入标头,刷新所有写缓冲区并结束请求(例如关闭套接字)。因此,您不能多次“结束”请求。由于您的results.forEach()循环是同步的,因此看来您可以将response.end()放在循环完成后的某个位置,因此只有在循环中的所有response.write()调用完成后才调用一次。

您还必须修复循环中的其他内容,因为您似乎决定在循环中间的某个位置,如果循环中的某一项不起作用,则将返回404。我不知道您应该在其中采用什么逻辑。也许您应该跳过任何通过if测试的项目,仅在不匹配的情况下发送404?

您还试图在循环内一遍又一遍地设置状态和特定的标头。那些只能有一个值,因此不清楚为什么要在循环中一遍又一遍地设置它。只有循环的最后一次迭代会停留。

因此,关于如何处理循环的逻辑确实存在缺陷。为了让我们知道如何重新制作循环以使其正常工作,我们必须更多地了解数据的外观以及您希望响应的外观。

要解决的问题列表:

  1. 每个请求只能拨打一次response.end()
  2. response.statuscode只能有一个值,因此不清楚为什么要在循环中多次调用它。
  3. 您在循环内确定404状态,但随后循环继续尝试写入其他值。这种设计实际上没有任何意义。也许您需要在遍历循环后决定是否应该基于在循环中找到的内容发送404。
  4. 您的服务器正在为它收到的每个请求调用此代码。希望那是因为您在发布时剥离了很多代码,因为您永远都不要这样做。您应该具有要检查的特定路径,并且仅在请求该路径时才执行所有这些工作。否则,当爬虫探测您的网站,浏览器要求提供图标时,您将完成所有这些工作。

您仍然没有真正解释您想要构建的响应,但是我会猜测。如果找到element.url.includes(request.url),则要发送该响应并停止循环并完成。如果您在element.url.includes(request.url)的任何一个中都找不到results,那么您想发送一个404。如果是这样,您可以这样做:

const server = http.createServer(function(request, response) {
    parse.allFiles().then(results => {
        // find first element.url that matches our request.url
        const match = results.find(element => element.url.includes(request.url));
        if (match) {
            let headerSplit = (match.headers + '').split('=');
            let headername = headerSplit[0];
            let headerVal = headerSplit[1];
            response.setHeader(headername, headerVal);
            response.write(JSON.stringify(match.body));
            response.statuscode = parseInt(match.status);
            response.end()
        } else {
            response.writeHead(404, {
                'Content-Type': 'text/plain'
            })
            response.end('No Page Found')
        }
    });
});