จะส่งข้อความสถานะ http แบบกำหนดเองใน node / express ได้อย่างไร?


90

แอปพลิเค Node.js ของฉันเป็นแบบจำลองเช่นด่วน / ตัวอย่าง / MVCแอป

ในการดำเนินการของคอนโทรลเลอร์ฉันต้องการคายสถานะ HTTP 400 ด้วยข้อความ http ที่กำหนดเอง โดยค่าเริ่มต้นข้อความสถานะ http คือ "คำขอไม่ถูกต้อง":

HTTP/1.1 400 Bad Request

แต่ฉันต้องการส่ง

HTTP/1.1 400 Current password does not match

ฉันลองใช้หลายวิธี แต่ไม่มีวิธีใดเลยที่ตั้งข้อความสถานะ http เป็นข้อความที่กำหนดเองของฉัน

ฟังก์ชันตัวควบคุมโซลูชันปัจจุบันของฉันมีลักษณะดังนี้:

exports.check = function( req, res) {
  if( req.param( 'val')!=='testme') {
    res.writeHead( 400, 'Current password does not match', {'content-type' : 'text/plain'});
    res.end( 'Current value does not match');

    return;
  } 
  // ...
}

ทุกอย่างทำงานได้ดี แต่ ... ดูเหมือนจะไม่ใช่วิธีที่ถูกต้อง

มีวิธีใดที่ดีกว่าในการตั้งค่าข้อความสถานะ http โดยใช้ express


4
นี่ดูเหมือนจะเป็นวิธีแก้ปัญหาเพียงอย่างเดียว แต่ฉันจะไม่แนะนำอะไรแบบนั้นข้อมูลจำเพาะ HTTP 1.1 มีคำอธิบายข้อผิดพลาดเป็นมาตรฐานด้วยเหตุผลที่ดีบางประการ ฉันคิดว่าการส่งรหัสสถานะที่รู้จักกันดีพร้อมคำอธิบายที่กำหนดเองนั้นเป็นวิธีปฏิบัติที่ไม่ดี แต่ขึ้นอยู่กับคุณ
schaermu

อืม - อาจจะจริง ในทางกลับกันฉันจะถือว่าเบราว์เซอร์ตรวจสอบรหัสสถานะไม่ใช่ข้อความสถานะ http ที่มนุษย์อ่านได้ ฉันคิดว่าเป็นความคิดที่ดีที่จะใช้ข้อความสถานะ http เพื่อส่งข้อความแสดงข้อผิดพลาดที่เป็นรูปธรรม (เช่นไม่ใช่ค่าเริ่มต้น) หากมี นอกจากนี้ยังง่ายต่อการจับโดยใช้สคริปต์ java ฝั่งไคลเอ็นต์ (โดยใช้ jQuery คุณสามารถทำ "jqXHR.statusText" เพื่อรับข้อผิดพลาดเพื่อการแสดงผล)
lgersman

4
ไม่เกี่ยวกับความเข้ากันได้หรือปัญหาเบราว์เซอร์ที่อาจเกิดขึ้น แต่เป็นเพียงการปฏิบัติที่ไม่ดี) หากคุณต้องการข้อความแสดงข้อผิดพลาดให้ส่งเป็นเนื้อหานั่นคือวัตถุประสงค์
schaermu

6
คำอธิบายข้อผิดพลาดเฉพาะไม่ได้เป็นส่วนหนึ่งของข้อมูลจำเพาะ RCF-2616 ระบุเฉพาะ: "ค่าแต่ละค่าของรหัสสถานะตัวเลขที่กำหนดไว้สำหรับ HTTP / 1.1 และชุดตัวอย่างของวลีเหตุผลที่เกี่ยวข้องแสดงอยู่ด้านล่างวลีเหตุผลที่แสดงในที่นี้เป็นเพียงคำแนะนำเท่านั้นซึ่งอาจถูกแทนที่ด้วย เทียบเท่าในท้องถิ่นโดยไม่ส่งผลกระทบต่อโปรโตคอล "
Ted Bigham

วลีเหตุผลที่กำหนดเองนั้นยอดเยี่ยม แต่ (เนื่องจากข้อความของคุณคือ "รหัสผ่านปัจจุบันไม่ตรงกัน" ") ดูเหมือนว่าคุณต้องการรหัส 401 ที่นี่ซึ่งในกรณีนี้คุณอาจไม่จำเป็นต้องเปลี่ยนข้อความ
Codebling

คำตอบ:


60

คุณสามารถตรวจสอบเอกสารres.send(400, 'Current password does not match') Look express 3.xเพื่อดูรายละเอียด

อัปเดตสำหรับ Expressjs 4.x

ใช้วิธีนี้ (ดูเอกสาร 4.x ด่วน ):

res.status(400).send('Current password does not match');
// or
res.status(400);
res.send('Current password does not match');

41
น่าเสียดายที่นี่จะไม่ตั้งค่าข้อความสถานะ http แต่จะส่ง 'รหัสผ่านปัจจุบันไม่ตรงกัน' เป็นเนื้อหาเนื้อหา ...
lgersman

สิ่งนี้ตั้งค่าสถานะ HTTP แต่จะแสดงคำเตือนเนื่องจากลายเซ็นวิธีนี้เลิกใช้แล้ว
nullability

1
res.status(400).send('Current password does not match');ตัวอย่างการทำงานสำหรับฉันสำหรับเอ็กซ์เพรส 4.
ไทเลอร์ถ่านหิน

ทำงานในExpress ^4.16.2
Ajay

105

คำตอบที่มีอยู่ไม่บรรลุตามที่ OP ขอไว้ในตอนแรกซึ่งเป็นการแทนที่Reason-Phrase ที่เป็นค่าเริ่มต้น(ข้อความที่ปรากฏหลังรหัสสถานะ) ที่ส่งโดย Express

สิ่งที่คุณต้องการคือres.statusMessage. นี่ไม่ใช่ส่วนหนึ่งของ Express แต่เป็นคุณสมบัติของอ็อบเจ็กต์ http.Response ที่อยู่ภายใต้ Node.js 0.11+

คุณสามารถใช้มันได้เช่นนี้ (ทดสอบใน Express 4.x):

function(req, res) {
    res.statusMessage = "Current password does not match";
    res.status(400).end();
}

จากนั้นใช้curlเพื่อตรวจสอบว่าใช้งานได้:

$ curl -i -s http://localhost:3100/
HTTP/1.1 400 Current password does not match
X-Powered-By: Express
Date: Fri, 08 Apr 2016 19:04:35 GMT
Connection: keep-alive
Content-Length: 0

6
นี่เป็นวิธีที่ถูกต้องในการตั้งค่าเป็นstatusMessageอย่างอื่นนอกเหนือจากข้อความมาตรฐานที่แมปกับ StatusCode
peteb

4
คุณสามารถรับทรัพย์สินในวัตถุต้นแบบด้วยres.nativeResponse.statusMessage
sebilasse

@RobertMoskal ทดสอบโดยใช้เซิร์ฟเวอร์ Express ขั้นต่ำ (Express 4.16.1 และ Node 12.9.0) และยังใช้งานได้สำหรับฉัน ตรวจสอบรหัสแอปพลิเคชันของคุณ: อาจมีบางอย่างผิดปกติ
mamacdon

ไม่แน่ใจว่าเหตุใดจึงไม่ใช่คำตอบที่ยอมรับเพราะแน่นอนว่าเป็นวิธีแก้ปัญหาอย่างน้อยก็ในขณะที่ฉันเขียนสิ่งนี้
Aaron Summers

1
สิ่งนี้ควรใช้ได้กับ HTTP1.1 ไม่ใช่ HTTP2: nodejs.org/dist/latest-v15.x/docs/api/…
Jokesterfr

12

ที่ฝั่งเซิร์ฟเวอร์ (มิดเดิลแวร์ Express):

if(err) return res.status(500).end('User already exists.');

จัดการที่ฝั่งไคลเอ็นต์

เชิงมุม:-

$http().....
.error(function(data, status) {
  console.error('Repos error', status, data);//"Repos error" 500 "User already exists."
});

jQuery: -

$.ajax({
    type: "post",
    url: url,
    success: function (data, text) {
    },
    error: function (request, status, error) {
        alert(request.responseText);
    }
});

11

วิธีหนึ่งที่สวยงามในการจัดการข้อผิดพลาดที่กำหนดเองเช่นนี้ในแบบด่วนคือ:

function errorHandler(err, req, res, next) {
  var code = err.code;
  var message = err.message;
  res.writeHead(code, message, {'content-type' : 'text/plain'});
  res.end(message);
}

(คุณยังสามารถใช้ express 'built-in express.errorHandlerสำหรับสิ่งนี้)

จากนั้นในมิดเดิลแวร์ของคุณก่อนเส้นทางของคุณ:

app.use(errorHandler);

จากนั้นที่คุณต้องการสร้างข้อผิดพลาด 'รหัสผ่านปัจจุบันไม่ตรงกัน':

function checkPassword(req, res, next) {
  // check password, fails:
  var err = new Error('Current password does not match');
  err.code = 400;
  // forward control on to the next registered error handler:
  return next(err);
}

err.status = 400; เป็นเรื่องธรรมดาที่ฉันเชื่อ
mkmelin


3

กรณีการใช้งานของฉันกำลังส่งข้อความแสดงข้อผิดพลาด JSON ที่กำหนดเองเนื่องจากฉันใช้ Express เพื่อเปิดใช้งาน REST API ฉันคิดว่านี่เป็นสถานการณ์ที่พบได้บ่อยดังนั้นจะเน้นที่คำตอบของฉัน

เวอร์ชั่นสั้น:

การจัดการข้อผิดพลาดด่วน

กำหนดมิดเดิลแวร์จัดการข้อผิดพลาดเหมือนกับมิดเดิลแวร์อื่น ๆ ยกเว้นมีอาร์กิวเมนต์สี่อาร์กิวเมนต์แทนที่จะเป็นสามโดยเฉพาะด้วยลายเซ็น (err, req, res, next) ... คุณกำหนดมิดเดิลแวร์จัดการข้อผิดพลาดเป็นอันดับสุดท้ายหลังจาก app.use () อื่นและกำหนดเส้นทางการโทร

app.use(function(err, req, res, next) {
    if (err instanceof JSONError) {
      res.status(err.status).json({
        status: err.status,
        message: err.message
      });
    } else {
      next(err);
    }
  });

เพิ่มข้อผิดพลาดจากจุดใดก็ได้ในโค้ดโดยทำ:

var JSONError = require('./JSONError');
var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);

เวอร์ชันยาว

วิธีที่ยอมรับได้ในการโยนข้อผิดพลาดคือ:

var err = new Error("Uh oh! Can't find something");
err.status = 404;
next(err)

โดยค่าเริ่มต้น Express จะจัดการสิ่งนี้โดยการบรรจุเป็น HTTP Response ด้วยรหัส 404 และเนื้อความประกอบด้วยสตริงข้อความที่ต่อท้ายด้วย stack trace

สิ่งนี้ไม่ได้ผลสำหรับฉันเมื่อฉันใช้ Express เป็นเซิร์ฟเวอร์ REST ฉันต้องการให้ส่งข้อผิดพลาดกลับเป็น JSON ไม่ใช่ HTML ฉันไม่ต้องการให้การติดตามสแต็กของฉันย้ายออกไปยังลูกค้าของฉันอย่างแน่นอน

ฉันสามารถส่ง JSON เป็นการตอบกลับโดยใช้req.json()เช่น. บางอย่างเช่นreq.json({ status: 404, message: 'Uh oh! Can't find something'}). อีกทางเลือกหนึ่งคือฉันสามารถตั้งรหัสสถานะโดยใช้req.status(). การรวมสอง:

req.status(404).json({ status: 404, message: 'Uh oh! Can't find something'});

การทำงานนี้เหมือนมีเสน่ห์ ที่กล่าวว่าฉันพบว่ามันค่อนข้างเทอะทะพิมพ์ทุกครั้งที่ผมมีข้อผิดพลาดและรหัสจะไม่-ตนเอง documenting เหมือนเราnext(err)เป็น ดูเหมือนมากเกินไปกับวิธีการส่ง JSON การตอบกลับปกติ (เช่นถูกต้อง) นอกจากนี้ข้อผิดพลาดใด ๆ ที่เกิดจากวิธีการยอมรับยังคงส่งผลให้เอาต์พุต HTML

นี่คือที่มาของมิดเดิลแวร์การจัดการข้อผิดพลาดของ Express ในฐานะส่วนหนึ่งของเส้นทางของฉันฉันกำหนด:

app.use(function(err, req, res, next) {
    console.log('Someone tried to throw an error response');
  });

ฉันยังมีข้อผิดพลาดคลาสย่อยในคลาส JSONError ที่กำหนดเอง:

JSONError = function (status, message) {
    Error.prototype.constructor.call(this, status + ': ' + message);
    this.status = status;
    this.message = message;
  };
JSONError.prototype = Object.create(Error);
JSONError.prototype.constructor = JSONError;

ตอนนี้เมื่อฉันต้องการโยนข้อผิดพลาดในรหัสฉันทำ:

var err = new JSONError(404, 'Uh oh! Can't find something');
next(err);

กลับไปที่ข้อผิดพลาดที่กำหนดเองในการจัดการมิดเดิลแวร์ฉันแก้ไขเป็น:

app.use(function(err, req, res, next) {
  if (err instanceof JSONError) {
    res.status(err.status).json({
      status: err.status,
      message: err.message
    });
  } else {
    next(err);
  }
}

Subclassing Error ลงใน JSONError เป็นสิ่งสำคัญเนื่องจากฉันสงสัยว่า Express จะinstanceof Errorตรวจสอบพารามิเตอร์แรกที่ส่งไปยัง a next()เพื่อตรวจสอบว่าต้องเรียกตัวจัดการปกติหรือตัวจัดการข้อผิดพลาด ฉันสามารถลบการinstanceof JSONErrorตรวจสอบและทำการแก้ไขเล็กน้อยเพื่อให้แน่ใจว่ามีข้อผิดพลาดที่ไม่คาดคิด (เช่นข้อขัดข้อง) และส่งคืนการตอบสนอง JSON ด้วย


3

เมื่อใช้ Axios คุณสามารถดึงข้อความตอบกลับที่กำหนดเองด้วย:

Axios.get(“your_url”)
.then(data => {
... do something
}.catch( err => {
console.log(err.response.data) // you want this
})

... หลังจากตั้งค่าใน Express เป็น:

res.status(400).send(“your custom message”)

ง่ายมากทำไมคนข้างบนคุณต้องทำให้เรื่องซับซ้อนขนาดนี้
iqbal125

0

หากเป้าหมายของคุณคือการลดให้เหลือเพียงบรรทัดเดียว / ง่ายๆคุณสามารถพึ่งพาค่าเริ่มต้นได้เล็กน้อย ...

return res.end(res.writeHead(400, 'Current password does not match'));

-2

ในกรณีของการ Restify เราควรใช้sendRaw()method

ไวยากรณ์คือ: res.sendRaw(200, 'Operation was Successful', <some Header Data> or null)

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.