【问题标题】:Another "can't set headers after they're sent"另一个“发送后无法设置标题”
【发布时间】:2018-09-27 22:37:39
【问题描述】:

我收到“发送后无法设置标头”错误,我知道这可能是由于我的服务器多次发送响应造成的,但我的代码似乎并非如此,至少在表面上。我向 dbpedia 查询以获得一些资源,然后将其发送回我的客户。代码如下:

app.get("/",function(req,res,next){
    if (req.query.titolo){
        var response ;
        let [ artist, title ] = getArtistTitle(req.query.titolo);
        title = title.replace(" ","_");//for dbpedia resource names
        const prefixes = {
            dbo: "http://dbpedia.org/ontology/",
            db: "http://dbpedia.org/resource/"
        }
        DbPediaClient.setOptions('application/sparql-results+json',prefixes);
        DbPediaClient.query("SELECT ?abstract WHERE { db:"+title+
        " dbo:abstract ?abstract. FILTER langMatches(lang(?abstract),'en') }")
        .then((data)=>{
            response = data["results"]["bindings"][0]["abstract"]["value"] ;
            return res.json({abstract: response}) ;
        })
        .catch((error)=>{
            console.log(error);
        });
    }
});

我使用 virtuoso-sparql-client 对http://dbpedia.org/sparql 进行查询(DbPediaClient 在此函数之外初始化)。我已经尝试过使用 res.send 而不是 res.json,但它仍然给出了同样的错误。顺便说一句:

Error: Can't set headers after they are sent.
    at validateHeader (_http_outgoing.js:491:11)
    at ServerResponse.setHeader (_http_outgoing.js:498:3)
    at ServerResponse.header (/home/lorenzo/Scrivania/ProgettoTechweb/AlphaTube/node_modules/express/lib/response.js:767:10)
    at ServerResponse.send (/home/lorenzo/Scrivania/ProgettoTechweb/AlphaTube/node_modules/express/lib/response.js:170:12)
    at DbPediaClient.query.then (/home/lorenzo/Scrivania/ProgettoTechweb/AlphaTube/server.js:43:15)
    at <anonymous>
    at process._tickCallback (internal/process/next_tick.js:188:7)

如果您需要更多信息,请询问。

【问题讨论】:

  • 除了这条路线,还有其他路线可以匹配"/"吗?
  • if (req.query.titolo){ 是否有更多的条件同时为真,例如if(...){} if(...){}
  • @PatrickRoberts 在此之前还有一个。 app.get("/",function(req,res,next){ //console.log(req.query); res.sendFile(path + "index.html"); next(); });
  • @Plutone11011 这就是问题所在。你总是res.sendFile()。所以您已经发送了 HTML,现在您正尝试在同一个请求/响应周期中发送 JSON,这表示您不能。
  • @vibhor1997a 我不这么认为,但我不确定你的意思。该条件用于检查 get 查询中包含的特定属性。基本上我希望这个中间件只响应客户端的特定 ajax 请求。

标签: node.js express sparql


【解决方案1】:

Express 是一个框架,它通过遍历与 HTTP 请求中指定的路径匹配的路由并让您的代码在每个匹配项中发送响应或调用 next()(如果没有发送)来处理请求/响应周期。这里的问题是您有以下问题:

app.get("/",function(req,res,next){
    res.sendFile(...);
    next();
});

app.get("/",function(req,res,next){
    if (req.query.titolo){
        ...
        res.json(...);
    }
});

这段代码的意思

每当我收到对/ 的 HTTP 请求然后发送一些 HTML,然后如果请求在查询中包含 titolo,也发送一些 JSON。

Express 告诉您,由于您已经发送了 HTML,因此您无法发送任何其他内容。

一种解决方案是将 API 路由移到 HTML 之上:

app.get("/",function(req,res,next){
    if (req.query.titolo){
        ...
        res.json(...);
    } else {
      next();
    }
});

app.get("/",function(req,res){
    res.sendFile(...);
});

意思是

每当我收到对/ 的HTTP 请求时,如果该请求在查询中包含titolo,则发送一些JSON,否则发送一些HTML。

但我的建议是将 API 路由移动到不与静态文件的路由冲突的不同路径,这对于 HTTP 服务器来说更为典型。

【讨论】:

    猜你喜欢
    • 2017-09-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多