簡體   English   中英

錯誤:發送HTTP節點服務器的標頭后,無法設置標頭

[英]Error: Can't set headers after they are sent for HTTP node server

我試圖根據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}”]},如果在服務器中傳遞url,例如localhost:8080 / account / 41,它將作為響應正文返回[“ {name:zyx}”]}]]作為響應。

您在.forEach()循環中有一個response.end() 這意味着您要多次調用它。 您只能為每個請求調用一次,因為當您調用它時,將寫入標頭,刷新所有寫緩沖區並結束請求(例如,關閉套接字)。 因此,您不能多次“結束”請求。 由於您的results.forEach()循環是同步的,因此您似乎可以在循環完成后將response.end()放在某個位置,因此僅在循環中所有response.write()調用完成后才調用一次。

您還必須修復循環中的其他內容,因為您似乎正在決定在循環中間的某個位置,如果循環中的某一項不起作用,則將返回404。 我不知道您應該在其中采用什么邏輯。 也許您應該跳過任何通過if測試的項目,如果沒有匹配項if僅發送404?

您還試圖在循環內一遍又一遍地設置狀態和特定的標頭。 那些只能有一個值,因此不清楚為什么要在循環中一遍又一遍地設置它。 只有循環的最后一次迭代會停留。

因此,關於如何處理循環的邏輯實際上只是有缺陷的。 為了使我們知道如何重新制作循環以使其正常工作,我們將必須更多地了解數據的外觀以及您希望響應的外觀。

要修復的問題列表:

  1. 每個請求只能調用一次response.end()
  2. response.statuscode只能有一個值,因此不清楚為什么要在循環中多次調用它。
  3. 您可以在循環內確定404狀態,但隨后循環將繼續嘗試寫入其他值。 這種設計實際上沒有任何意義。 也許您需要在遍歷循環后決定是否應基於在循環中找到的內容發送404消息。
  4. 您的服務器正在為收到的每個單個請求調用此代碼。 希望那是因為您在發布時剝離了很多代碼,因為您永遠都不要這樣做。 您應該具有要檢查的特定路徑,並且僅在請求該路徑時才執行所有這些工作。 否則,當爬蟲探測您的網站,瀏覽器要求提供圖標時,您將完成所有這些工作。

您仍然沒有真正解釋您要構建的響應,但是我會猜測。 如果找到element.url.includes(request.url) ,那么您想發送該響應並停止循環並完成。 如果您在任何一個results都沒有找到element.url.includes(request.url) ,那么您想發送一個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')
        }
    });
});

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM