[javascript] 오류 : 클라이언트로 전송 된 헤더를 설정할 수 없습니다

Node.js를 처음 접했고 몇 가지 문제가 있습니다.

Node.js 4.10 및 Express 2.4.3을 사용하고 있습니다.

내가 접근하려고 할 때 http://127.0.0.1:8888/auth/facebook , 내가로 연결됩니다 http://127.0.0.1:8888/auth/facebook_callback .

그런 다음 다음 오류가 발생했습니다.

Error: Can't render headers after they are sent to the client.
    at ServerResponse.<anonymous> (http.js:573:11)
    at ServerResponse._renderHeaders (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:64:25)
    at ServerResponse.writeHead (http.js:813:20)
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/auth.strategies/facebook.js:28:15
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:113:13
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/strategyExecutor.js:45:39)
    at [object Object].pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:32:3)
    at [object Object].halt (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:29:8)
    at [object Object].redirect (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/authExecutionScope.js:16:8)
    at [object Object].<anonymous> (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/auth.strategies/facebook.js:77:15)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:195:11)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at param (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:189:13)
    at pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:191:10)
    at Object.router [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:197:6)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at param (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:189:13)
    at pass (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:191:10)
    at Object.router [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/router.js:197:6)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at Object.auth [as handle] (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect-auth/lib/index.js:153:7)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at HTTPServer.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:211:3)
    at Object.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:105:14)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:150:23)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at HTTPServer.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:211:3)
    at Object.handle (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:105:14)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:198:15)
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:323:9
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:338:9

node.js:134
        throw e; // process.nextTick error, or 'error' event on first tick
        ^
Error: Can't set headers after they are sent.
    at ServerResponse.<anonymous> (http.js:527:11)
    at ServerResponse.setHeader (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/patch.js:50:20)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:162:13)
    at next (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/http.js:207:9)
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:323:9
    at /home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session.js:338:9
    at Array.<anonymous> (/home/eugene/public_html/all_things_node/projects/fb2/node_modules/connect/lib/middleware/session/memory.js:57:7)
    at EventEmitter._tickCallback (node.js:126:26)

다음은 내 코드입니다.

var fbId= "XXX";
var fbSecret= "XXXXXX";
var fbCallbackAddress= "http://127.0.0.1:8888/auth/facebook_callback"

var cookieSecret = "node";     // enter a random hash for security

var express= require('express');
var auth = require('connect-auth')
var app = express.createServer();


app.configure(function(){
    app.use(express.bodyParser());
    app.use(express.methodOverride());
    app.use(express.cookieParser());
    app.use(express.session({secret: cookieSecret}));
    app.use(auth([
        auth.Facebook({
            appId : fbId,
            appSecret: fbSecret,
            callback: fbCallbackAddress,
            scope: 'offline_access,email,user_about_me,user_activities,manage_pages,publish_stream',
            failedUri: '/noauth'
        })
    ]));
    app.use(app.router);
});


app.get('/auth/facebook', function(req, res) {
  req.authenticate("facebook", function(error, authenticated) {
    if (authenticated) {
      res.redirect("/great");
      console.log("ok cool.");
      console.log(res['req']['session']);
    }
  });
});

app.get('/noauth', function(req, res) {
  console.log('Authentication Failed');
  res.send('Authentication Failed');
});

app.get('/great', function( req, res) {
  res.send('Supercoolstuff');
});

app.listen(8888);

내 코드에 어떤 문제가 있는지 알 수 있습니까?



답변

resExpress 의 객체는 Node.js의http.ServerResponse 하위 클래스입니다 ( http.js 소스 읽기 ). 전화 res.setHeader(name, value)할 때까지 원하는만큼 전화를 걸 수 res.writeHead(statusCode)있습니다. 이후 writeHead에는 헤더가 구워지고, 만 호출 할 수 res.write(data)있으며 마지막으로res.end(data) .

오류 : “오류 : 헤더를 보낸 후 설정할 수 없습니다.” 은 이미 본문 또는 완료 상태에 있지만 일부 함수가 헤더 또는 statusCode를 설정하려고 시도했음을 의미합니다. 이 오류가 표시되면 일부 본문이 이미 작성된 후 헤더를 보내려는 항목을 찾으십시오. 예를 들어 실수로 두 번 호출 된 콜백이나 본문이 전송 된 후 발생하는 오류를 찾으십시오.

귀하의 경우에 전화를 걸어 res.redirect()응답이 완료되었습니다. 그런 다음 코드에서 오류가 발생했습니다 ( res.reqis null). function(req, res, next)콜백이 아닌 실제 내에서 오류가 발생했기 때문에 Connect는이 오류를 잡아 500 오류 페이지를 보내려고했습니다. 그러나 헤더가 이미 전송되었으므로 Node.js는setHeader 는 본 오류를 던졌습니다.

Node.js / Express 응답 메소드의 포괄적 인 목록 및 호출시기 :

응답에 있어야 헤드 및 유지 헤드 :

  1. res.writeContinue()
  2. res.statusCode = 404
  3. res.setHeader(name, value)
  4. res.getHeader(name)
  5. res.removeHeader(name)
  6. res.header(key[, val]) (익스프레스 만)
  7. res.charset = 'utf-8' (Express 만 해당, Express 특정 방법에만 영향을 미침)
  8. res.contentType(type) (익스프레스 만)

응답은 Head에 있어야하며 Body 가됩니다 .

  1. res.writeHead(statusCode, [reasonPhrase], [headers])

응답 중 하나 일 수 있습니다 헤드 / 바디 와 남아 바디 :

  1. res.write(chunk, encoding='utf8')

응답 중 하나 일 수 있습니다 헤드 / 바디 및됩니다 완료 :

  1. res.end([data], [encoding])

응답은 헤드 / 바디 일 수 있으며 현재 상태를 유지합니다.

  1. res.addTrailers(headers)

응답에 있어야 헤드 및됩니다 완료 :

  1. return next([err]) (연결 / 표현 만)
  2. 미들웨어 내의 모든 예외 function(req, res, next)(Connect / Express 만 해당)
  3. res.send(body|status[, headers|status[, status]]) (익스프레스 만)
  4. res.attachment(filename) (익스프레스 만)
  5. res.sendfile(path[, options[, callback]]) (익스프레스 만)
  6. res.json(obj[, headers|status[, status]]) (익스프레스 만)
  7. res.redirect(url[, status]) (익스프레스 만)
  8. res.cookie(name, val[, options]) (익스프레스 만)
  9. res.clearCookie(name[, options]) (익스프레스 만)
  10. res.render(view[, options[, fn]]) (익스프레스 만)
  11. res.partial(view[, options]) (익스프레스 만)

답변

나는이 오류를 잠시 동안 만났다. 내 머리를 감아 서 여기에 참고로 쓰고 싶었다고 생각합니다.

메소드를 사용하여 연결 하거나 표현 하기 위해 (미리 연결되어있는) 미들웨어를 추가 할 때 연결에app.use 항목을 추가 Server.prototype.stack하고 있습니다 (적어도 현재와 npm install connect같이,이 게시물과 같이 하나의 github와는 상당히 다릅니다). 서버가 요청을 받으면 스택을 반복하여 (request, response, next)메소드를 호출합니다 .

문제는 미들웨어 중 하나에서 항목이 응답 본문 또는 헤더에 쓰지만 ( 어떤 이유로 든 또는 어떤 이유로 보이는지) 호출하지 않고 전화 response.end()를 거는 것입니다.next() 핵심 Server.prototype.handle메소드가 완료되면 하는 것입니다. 그:

  1. 스택에 더 이상 아이템이 없거나
  2. 그것은 response.headerSent사실이다.

따라서 오류가 발생합니다. 그러나 발생하는 오류는 연결 http.js소스 코드 의 기본 응답입니다 .

res.statusCode = 404;
res.setHeader('Content-Type', 'text/plain');
res.end('Cannot ' + req.method + ' ' + req.url);

거기에서 response.end ()를 호출하지 않고 메소드 res.setHeader('Content-Type', 'text/plain');에서 설정했을 가능성이있는 을 호출합니다 .render

response.setHeader("Content-Type", "text/html");
response.write("<p>Hello World</p>");

모든 것을 구성해야하는 방법은 다음과 같습니다.

좋은 미들웨어

// middleware that does not modify the response body
var doesNotModifyBody = function(request, response, next) {
  request.params = {
    a: "b"
  };
  // calls next because it hasn't modified the header
  next();
};

// middleware that modify the response body
var doesModifyBody = function(request, response, next) {
  response.setHeader("Content-Type", "text/html");
  response.write("<p>Hello World</p>");
  response.end();
  // doesn't call next()
};

app.use(doesNotModifyBody);
app.use(doesModifyBody);

문제가있는 미들웨어

var problemMiddleware = function(request, response, next) {
  response.setHeader("Content-Type", "text/html");
  response.write("<p>Hello World</p>");
  next();
};

문제가있는 미들웨어는 호출 response.end()및 호출 없이 응답 헤더를 설정하여 next()connect의 서버를 혼란스럽게합니다.


답변

이 Q & A의 일부 답변이 잘못되었습니다. 허용되는 답변도 “실제적인”것은 아니므로 더 간단한 용어로 설명하는 답변을 게시하고 싶습니다. 내 대답은 반복해서 게시 된 오류의 99 %를 다룰 것입니다. 오류의 실제 원인으로 허용되는 답변을 살펴보십시오.


HTTP는 요청 당 하나의 응답이 필요한주기를 사용합니다. 클라이언트가 요청 (예 : POST 또는 GET)을 보내면 서버는 하나의 응답 만 다시 보내야합니다.

이 오류 메시지 :

오류 : 헤더를 보낸 후 설정할 수 없습니다.

일반적으로 한 요청에 여러 응답을 보낼 때 발생합니다. 다음 함수는 요청 당 한 번만 호출되어야합니다.

  • res.json()
  • res.send()
  • res.redirect()
  • res.render()

(그리고 거의 사용되지 않는 몇 가지, 허용되는 답변을 확인하십시오)

이러한 res 함수가 호출 될 때 경로 콜백은 반환되지 않습니다. 함수의 끝이나 return 문에 도달 할 때까지 계속 실행됩니다. 응답을 보낼 때 돌아 오려면 다음과 같이하십시오 : return res.send().


이 코드를 예로 들어 보겠습니다.

app.post('/api/route1', function(req, res) {
  console.log('this ran');
  res.status(200).json({ message: 'ok' });
  console.log('this ran too');
  res.status(200).json({ message: 'ok' });
}

POST 요청이 / api / route1로 전송 되면 콜백의 모든 라인이 실행됩니다. 가 전송 된 후 캔은 헤더를 설정하지 때문에 오류 메시지가 발생합니다 res.json()두 번 호출되는 두 개의 응답이 전송됩니다 의미.

요청 당 하나의 응답 만 보낼 수 있습니다!


위의 코드 샘플의 오류는 명백했습니다. 보다 일반적인 문제는 여러 가지가있는 경우입니다.

app.get('/api/company/:companyId', function(req, res) {
  const { companyId } = req.params;
  Company.findById(companyId).exec((err, company) => {
      if (err) {
        res.status(500).json(err);
      } else if (!company) {
        res.status(404).json();      // This runs.
      }
      res.status(200).json(company); // This runs as well.
    });
}

콜백이 첨부 된이 경로는 데이터베이스에서 회사를 찾습니다. 존재하지 않는 회사에 대한 쿼리를 수행하면 else if지점에 들어가서 404 응답을 보냅니다. 그 후에, 우리는 다음 문장으로 계속해서 응답을 보냅니다. 이제 두 개의 응답을 보냈으며 오류 메시지가 나타납니다. 응답을 하나만 보내도록하여이 코드를 수정할 수 있습니다.

.exec((err, company) => {
  if (err) {
    res.status(500).json(err);
  } else if (!company) {
    res.status(404).json();         // Only this runs.
  } else {
    res.status(200).json(company);
  }
});

또는 응답이 전송 될 때 돌아갑니다.

.exec((err, company) => {
  if (err) {
    return res.status(500).json(err);
  } else if (!company) {
    return res.status(404).json();  // Only this runs.
  }
  return res.status(200).json(company);
});

큰 죄인은 비동기 함수입니다. 질문 에서 다음 과 같은 기능을 수행 하십시오 .

article.save(function(err, doc1) {
  if (err) {
    res.send(err);
  } else {
    User.findOneAndUpdate({ _id: req.user._id }, { $push: { article: doc._id } })
    .exec(function(err, doc2) {
      if (err) res.send(err);
      else     res.json(doc2);  // Will be called second.
    })

    res.json(doc1);             // Will be called first.
  }
});

findOneAndUpdate()코드 샘플 에는 비동기 함수 ( )가 있습니다. 오류가 없으면 ( err) findOneAndUpdate()이 호출됩니다. 이 함수는 비동기식이므로 res.json(doc1)즉시 호출됩니다. 에 오류가 없다고 가정합니다 findOneAndUpdate(). res.json(doc2)에서는 else다음 호출됩니다. 두 개의 응답이 전송되었으며 헤더를 설정할 수 없습니다 오류 메시지가 나타납니다.

이 경우 수정은을 제거하는 것 res.json(doc1)입니다. 두 문서를 모두 클라이언트로 다시 보내려면 다른 문서를로 res.json()작성할 수 있습니다 res.json({ article: doc1, user: doc2 }).


답변

나는 똑같은 문제가 있었고 명령문 res.redirect없이 호출했기 때문에 그것이 즉시 호출되었다는 것을 깨달았습니다 .returnnext

auth.annonymousOnly = function(req, res, next) {
    if (req.user) res.redirect('/');
    next();
};

어느 것이 좋을까 :

auth.annonymousOnly = function(req, res, next) {
    if (req.user) return res.redirect('/');
    next();
};


답변

많은 사람들이이 오류에 부딪쳤다. 비동기 처리와 혼동됩니다. 아마도 일부 코드는 첫 번째 틱에서 헤더를 설정하고 향후 틱에서 비동기 콜백을 실행 중일 것입니다. 그 사이에 응답 헤더가 전송되지만 30X 리디렉션과 같은 추가 헤더는 추가 헤더를 추가하려고 시도하지만 응답 헤더가 이미 전송되었으므로 너무 늦습니다.

정확히 무엇이 오류의 원인인지 확실하지 않지만 조사 할 수있는 영역으로 콜백을 확인하십시오.

코드를 단순화하는 간단한 팁 제거 app.configure()하고 전화하십시오app.use 최상위 범위에서 직접 하십시오.

Facebook 및 12 개 이상의 타사 인증 제공 업체를 수행 하는 everyauth 모듈 도 참조하십시오 .


답변

나는이 문제에 대해 머리를 끓 였고 콜백 처리에 대한 부주의 한 실수로 인해 발생했습니다. 반환되지 않은 콜백은 응답을 두 번 설정합니다.!

내 프로그램에는 요청을 확인하고 DB를 쿼리하는 코드가 있습니다. 오류가 있는지 확인한 후 유효성 검사 오류가있는 index.js를 다시 호출했습니다. 그리고 유효성 검사가 통과하면 성공 / 실패로 db에 도달합니다.

    var error = validateRequestDetails("create",queryReq);
    if (error)
        callback(error, null);
   else
    some code
    callback(null, success);

발생한 일 : 유효성 검사에 실패하면 콜백 호출 및 응답 설정이 실패합니다. 그러나 반환되지 않았습니다. 따라서 여전히 방법이 db로 이동하여 success / failure에 도달합니다. 동일한 콜백을 다시 호출하여 응답이 두 번 설정되었습니다.

따라서 해결책은 간단합니다. 오류가 발생하면 메소드가 계속 실행되지 않도록 콜백을 ‘반환’해야하므로 응답 객체를 한 번 설정해야합니다

  var error = validateRequestDetails("create",queryReq);
    if (error)
        callback(error, null);
        return;
    else
       some code
       callback(null, success);


답변

응답을 보낸 후 명령문을 전달하면 이러한 유형의 오류가 발생합니다.

예를 들면 다음과 같습니다.

res.send("something response");
console.log("jhgfjhgsdhgfsdf");
console.log("sdgsdfhdgfdhgsdf");
res.send("sopmething response");

응답이 전송되면 다음 res.send이 실행되지 않기 때문에보고있는 오류가 발생합니다 .

원하는 것을하려면 응답을 보내기 전에해야합니다.