Javascript 错误[ERR\u HTTP\u HEADERS\u SENT]:发送到客户端后无法设置头(POST方法)

Javascript 错误[ERR\u HTTP\u HEADERS\u SENT]:发送到客户端后无法设置头(POST方法),javascript,node.js,express,Javascript,Node.js,Express,我对Node很陌生;我查了一下,但不懂一些术语 代码的目的:URL缩短器post方法 我之所以出现此错误,是因为我试图将一个具有未定义DNS地址的URL发布到MongoDB(例如,通过了https的正则表达式测试,但出现以下错误) 模式和模型: var urlSchema = new mongoose.Schema({ url: String, shortUrl: String }); var Url = mongoose.model("Url", urlSchema

我对Node很陌生;我查了一下,但不懂一些术语

代码的目的:URL缩短器post方法

我之所以出现此错误,是因为我试图将一个具有未定义DNS地址的URL发布到MongoDB(例如,通过了https的正则表达式测试,但出现以下错误)

模式和模型:

var urlSchema = new mongoose.Schema({
  url: String,
  shortUrl: String
});
var Url = mongoose.model("Url", urlSchema);
post处理程序的代码:

app.post("/api/shorturl/new", function(req, res) {
  var url = req.body.url;
  console.log(url);
  var httpRegex = /^(https?:\/\/)/;
  if (!httpRegex.test(url)) {
    res.json({ error: "invalid url" });
    return;
  }
  if (/^(https:\/\/)/.test(url)) {
    var httpsDroppedUrl = url.slice(8);
    dns.lookup(httpsDroppedUrl, function(err, address, family) {
      console.log("address: %j family: IPv%s", address, family);
      if (address == undefined) {
        res.json({ error: "invalid url" });
        return;
      }
    });
  } else {
    var httpDroppedUrl = url.slice(7);
    dns.lookup(httpDroppedUrl, function(err, address, family) {
      console.log("address: %j family: IPv%s", address, family);
      if (address == undefined) {
        res.json({ error: "invalid url" });
        return;
      }
    });
  }

  var newUrl =
    (Math.floor(Math.sqrt(url.length)) * 3).toString() +
    +Math.floor(Math.random() * 9999).toString() +
    Math.floor(Math.random() * 500).toString(); //random method to generate unique identifier
  console.log(newUrl);

  var data = new Url({
    url: url,
    shortUrl: newUrl
  });

  data.save(function(err) {
    if (err) {
      res.send("Error; please try again");
    }
  });

  res.json(data);
});
以下是我得到的完整错误:

_http_outgoing.js:467
    throw new ERR_HTTP_HEADERS_SENT('set');
    ^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
    at ServerResponse.setHeader (_http_outgoing.js:467:11)
    at ServerResponse.header (/rbd/pnpm-volume/10bcf34e-5673-48ca-b962-5eaef435922b/node_modules/.registry.npmjs.org/express/4.17.1/node_modules/express/lib/response.js:771:10)
    at ServerResponse.send (/rbd/pnpm-volume/10bcf34e-5673-48ca-b962-5eaef435922b/node_modules/.registry.npmjs.org/express/4.17.1/node_modules/express/lib/response.js:170:12)
    at ServerResponse.json (/rbd/pnpm-volume/10bcf34e-5673-48ca-b962-5eaef435922b/node_modules/.registry.npmjs.org/express/4.17.1/node_modules/express/lib/response.js:267:15)
at /app/server.js:58:13
    at processTicksAndRejections (internal/process/task_queues.js:83:17)
编辑1:
next()
替换为
return


我不确定我的代码哪里出错了

您需要将所有
next()
调用替换为
return
,因为:

  • res.send/json
    之后不需要
    next()
    ——它们已经设置了状态并向客户端发送响应
  • 在每个
    res.send/json
    之后添加
    return
    ,因为调用
    res.send/json
    不会立即从此处理程序返回您
  • 此外,您还需要使用承诺将
    dns.lookup
    调用转换为异步函数,因为现在它们不等待结果,并且立即继续执行

    函数dnsLookup(url){
    返回新承诺((解决、拒绝)=>{
    查找(url、函数(错误、地址、族){
    console.log(“地址:%j系列:IPv%s”,地址,系列);
    如果(地址==未定义){
    //您可以在这里调用reject(新错误(“无效url”),并在外部函数中捕获它
    解析({错误:“无效url”});
    返回;
    }
    解决();
    });
    }
    }
    
    if(/^(https:\/\/)/.test(url)){
    var httpsdroppedrl=url.slice(8);
    const lookupResult=等待dnsLookup(httpsdroppedrl);
    if(lookupResult.error){
    res.json({error:lookupResult.error});
    返回;
    }
    }
    
    当您使用
    res.json
    时,您不需要调用
    next()
    ,因为
    请求-响应循环已经结束。
    next()
    用于您希望请求内容通过请求和响应之间的多个中间件。我尝试删除所有next())调用,但其行为相同。出于某种原因,
    var-httpsdroppedrl=url.slice(8);
    直接在
    var-newUrl=(Math.floor(Math.sqrt(url.length))*3.toString()++Math.floor(Math.random()*9999).toString()+Math.floor(Math.random()*500).toString();console.log(newUrl)之前执行;
    然后它在dns.lookup内部进行回调。为什么它会从httpsdrookedURL跳到新URL,然后再跳回到dns.lookup?我怀疑
    lookup
    是一个异步函数,这意味着它在后台执行,直到得到结果,而不依赖它的其余代码会继续运行继续执行。我同意Anatoly下面的回答。当你有多个
    res.json
    时,你需要将
    return
    放在它们前面,除了最后一个。有没有办法将剩余代码的执行延迟到异步函数完成执行之后?我替换了每个
    next()
    使用
    返回
    但是我仍然面临着我以前遇到的问题。你能用最新的代码更新你的帖子吗?我刚刚更新了,我看到了另一个问题:
    dns。lookup
    立即返回,因为它的延续是在一个传递的回调中。也许最好将整个请求处理程序转换为异步并包装所有
    dns.lookup
    调用具有
    新承诺的函数
    。这样,代码将非常直接地工作,并且更像您计划的那样工作。