nginx 与 nodejs:502 错误网关错误
所以我的应用程序是用nodejs编写的,并且使用digitalocean Droplet(2GB RAM | 1 CPU | 50GB SSD),
所以我只针对一个特定的GET请求收到标题中提到的错误。该 GET 请求处理数据并呈现 PDF 文件。
当我检查 nginx 错误日志时,每次点击此 URL 时,我都会看到三行错误。以下是
- 过早关闭连接的
- 连接到上游时从上游connect() 读取响应头失败(111 连接被拒绝)时上游
- 错误连接到上游时没有实时上游
所以,我开始研究这些错误,并按照建议尝试了很多我的 nginx 配置文件中的配置更改
- ,例如添加增加的读取超时等,
- 添加增加的代理缓冲,
- 禁用 gzip
- ,添加上游块等,
这是我第一次使用 nginx。我按照 YouTube 教程在域上部署我的应用程序,然后还添加了 SSL 证书(尽管必须承认,在花了整整两天的时间尝试排除故障后,我现在确实了解了反向代理如何工作和配置的基本概念这个问题,所以我想知道是什么导致了这个问题)。
在此之前,我已将应用程序部署在 heroku 的免费层上,并且在此特定 URL 上的 GET 请求没有遇到任何问题。
以下是我当前的配置文件。就是在这条路
/etc/nginx/sites-available/default
upstream localhost:3000 {
zone upstreams 64K;
server 127.0.0.1:3000 max_fails=0 fail_timeout=2s;
keepalive 8;
}
server {
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name digitalawb.in www.digitalawb.in;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-Ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://localhost:3000/;
proxy_read_timeout 90;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 24 4k;
proxy_busy_buffers_size 8k;
proxy_max_temp_file_size 2048m;
proxy_temp_file_write_size 32k;
proxy_redirect http://localhost:3000/ https://digitalawb.in/;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/digitalawb.in/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/digitalawb.in/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
if ($host = www.digitalawb.in){
return 301 https://$host$request_uri;
}
if ($host = digitalawb.in){
return 301 https://$host$request_uri;
}
listen 80 default_server;
listen [::]:80 default_server;
server_name digitalawb.in www.digitalawb.in;
return 404;
}
另外,以下是位于以下位置的 nginx.conf 文件的内容
/etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
#multi_accept on;
}
http {
# Basic Settings
sendfile on;
top_nopush on;
top_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
#SSL settings
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
#Logging settings
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
#Gzip settings
gzip on;
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+res text/javascript;
#virtual host configs
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
以下是我的nodejs代码详细信息
- 主要功能
exports.boxSticker = async(req, res, next) => {
try{
let orderId = req.params.orderId
let userId = req.user.id
let order = await Order.findById(orderId).populate('client').exec()
let user = await User.findById(userId)
const doc = new PDFdocument({
autoFirstPage: false
})
if(order.boxDetails.length == 0){
return res.render('error', {message: `No Box Details added. Please add Box Details first before generating AWB`, statusCode: '400'})
}
const canvas = createCanvas()
const context = canvas.getContext('2d')
JsBarcode(canvas, order.awbNumber)
canvas.toBuffer((err, buffer) => {
if(err) next(err)
fsPromises.writeFile(`box_${order.awbNumber}.png`, buffer)
.then(() => {
for(let i = 0; i < order.numberOfBoxes; i++){
doc.addPage()
boxstickergenerate(i, doc, order, user)
}
})
.catch((err) => next(err))
})
res.setHeader('Content-type', 'application/pdf')
res.set({ 'Content-Disposition': `inline; filename=boxsticker_${order.awbNumber}.pdf` })
stream = doc.pipe(res)
doc.end()
stream.on('finish', () => {
fs.unlink(`box_${order.awbNumber}.png`, (err) => {
if(err) next(err)
})
})
}catch(err){
next(err)
}
}
- boxstickergenerate 功能
exports.boxstickergenerate = (current, doc, order, user) => {
doc.info['Title'] = `boxsticker${order.awbNumber}`
doc
.fillColor('black')
.rect(40, 75, 150, 30).fill()
.lineWidth(1.5)
.moveTo(40, 120)
.lineTo(560, 120).stroke()
doc
.fillColor('white')
.font('Helvetica-Bold')
.fontSize(20)
.text(order.service, 40, 80)
doc.fillColor('black')
.font('Helvetica-Bold')
.fontSize(11)
.text('FROM', 40, 140)
.font('Helvetica')
.text(order.consignor, 40, 155)
.text(`${order.consignorAddress1}, ${order.consignorAddress2}, ${order.consignorCity}, ${order.consignorState}, ${order.consignorPincode}`, 40, 170, {width: 350, align:'left'})
.font('Helvetica-Bold')
.text(order.origin, 40, 215)
.font('Helvetica')
.text(`TEL NO: ${order.consignorContactNumber}`, 40, 230)
.lineWidth(1.5)
.moveTo(40, 260)
.lineTo(560, 260).stroke()
.font('Helvetica-Bold')
.fontSize(16)
.text(`BOX NO ${current + 1}/${order.numberOfBoxes}`, 465, 140, {width: 100, align:'left'})
.rect(440, 160, 115, 30).fill()
.rect(440, 210, 115, 30).fill()
.fillColor('white')
.fontSize(11)
.text(order.client.username, 445, 165)
.text(order.service, 445, 215)
.fillColor('black')
.font('Helvetica-Bold')
.fontSize(16)
.text('TO', 40, 270)
.font('Helvetica')
.text(order.consignee, 40, 290)
.text(`${order.consigneeAddress1}, ${order.consigneeAddress2}, ${order.consigneeCity}, ${order.consigneeState}, ${order.consigneePincode}`, 40, 310, {width: 450, align:'left'})
.font('Helvetica-Bold')
.text(order.destination, 40, 370)
.font('Helvetica')
.text(`TEL NO: ${order.consigneeContactNumber}`, 40, 390)
.lineWidth(1.5)
.moveTo(40, 410)
.lineTo(560, 410).stroke()
.fontSize(14)
.text(`SHIPMENT DATE:`, 40, 430)
.text(moment(order.bookingDate).format(shortDateFormat), 160, 430)
.text(`SHIPMENT WEIGHT: ${order.chargeableWeight}`, 40, 450)
.text(`NO OF BOX: ${order.numberOfBoxes}`, 40, 470)
.text(`WAYBILL NO: ${order.awbNumber}`, 300, 450)
//.image(`box_${order.awbNumber}.png`, 265, 490, {width: 80, align:'center'})
.lineWidth(1.5)
.moveTo(40, 550)
.lineTo(560, 550).stroke()
.text('Office Purpose Only', 230, 570, {width: 150, align:'center'})
//.image(`box_${order.awbNumber}.png`, 265, 590, {width: 80, align:'center'})
.lineWidth(1.5)
.moveTo(40, 650)
.lineTo(560, 650).stroke()
.text(user.username, 230, 670, {width: 150, align:'center'})
}
so my app is written in nodejs and am using digitalocean droplet ( 2GB RAM | 1 CPU | 50gb SSD )
so I am getting the error as mentioned in the title only for one particular GET request. That GET requests processes data and renders a PDF file.
When i checked the nginx error logs, I see three lines of error throw up each time this URL is hit. Following are the errors
- upstream prematurely closed connection while reading response header from upstream
- connect() failed (111 connection refused) while connecting to upstream
- no live upstreams while connecting to upstream
So, I started my research on these errors, and as suggested tried a lot of configuration changes in my nginx config file like
- adding increased read timeouts, etc
- adding increased proxy buffering
- disabling gzip
- adding an upstream block and such
This is my first time using nginx. I followed a youtube tutorial to deploy my app on a domain and then add a SSL certificate as well (though have to admit I do understand now the basic concepts of how reverse proxy works and configuring after spending two full days trying to troubleshoot this problem, so I wonder what is it that is causing this issue).
Before this I had deployed the app on the free tier of heroku and I faced no issue with this GET request on this particular URL.
Following is my current configuration file. It is at this path
/etc/nginx/sites-available/default
upstream localhost:3000 {
zone upstreams 64K;
server 127.0.0.1:3000 max_fails=0 fail_timeout=2s;
keepalive 8;
}
server {
root /var/www/html;
index index.html index.htm index.nginx-debian.html;
server_name digitalawb.in www.digitalawb.in;
location / {
proxy_set_header Host $host;
proxy_set_header X-Real-Ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://localhost:3000/;
proxy_read_timeout 90;
proxy_buffering on;
proxy_buffer_size 4k;
proxy_buffers 24 4k;
proxy_busy_buffers_size 8k;
proxy_max_temp_file_size 2048m;
proxy_temp_file_write_size 32k;
proxy_redirect http://localhost:3000/ https://digitalawb.in/;
}
listen [::]:443 ssl ipv6only=on; # managed by Certbot
listen 443 ssl; # managed by Certbot
ssl_certificate /etc/letsencrypt/live/digitalawb.in/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/digitalawb.in/privkey.pem;
include /etc/letsencrypt/options-ssl-nginx.conf;
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
}
server {
if ($host = www.digitalawb.in){
return 301 https://$host$request_uri;
}
if ($host = digitalawb.in){
return 301 https://$host$request_uri;
}
listen 80 default_server;
listen [::]:80 default_server;
server_name digitalawb.in www.digitalawb.in;
return 404;
}
Also following is the content of the nginx.conf file which is at the following location
/etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 768;
#multi_accept on;
}
http {
# Basic Settings
sendfile on;
top_nopush on;
top_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
# server_tokens off;
# server_names_hash_bucket_size 64;
# server_name_in_redirect off;
include /etc/nginx/mime.types;
default_type application/octet-stream;
#SSL settings
ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;
#Logging settings
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
#Gzip settings
gzip on;
# gzip_vary on;
# gzip_proxied any;
# gzip_comp_level 6;
# gzip_buffers 16 8k;
# gzip_http_version 1.1;
# gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+res text/javascript;
#virtual host configs
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Following are my nodejs code details
- Main function
exports.boxSticker = async(req, res, next) => {
try{
let orderId = req.params.orderId
let userId = req.user.id
let order = await Order.findById(orderId).populate('client').exec()
let user = await User.findById(userId)
const doc = new PDFdocument({
autoFirstPage: false
})
if(order.boxDetails.length == 0){
return res.render('error', {message: `No Box Details added. Please add Box Details first before generating AWB`, statusCode: '400'})
}
const canvas = createCanvas()
const context = canvas.getContext('2d')
JsBarcode(canvas, order.awbNumber)
canvas.toBuffer((err, buffer) => {
if(err) next(err)
fsPromises.writeFile(`box_${order.awbNumber}.png`, buffer)
.then(() => {
for(let i = 0; i < order.numberOfBoxes; i++){
doc.addPage()
boxstickergenerate(i, doc, order, user)
}
})
.catch((err) => next(err))
})
res.setHeader('Content-type', 'application/pdf')
res.set({ 'Content-Disposition': `inline; filename=boxsticker_${order.awbNumber}.pdf` })
stream = doc.pipe(res)
doc.end()
stream.on('finish', () => {
fs.unlink(`box_${order.awbNumber}.png`, (err) => {
if(err) next(err)
})
})
}catch(err){
next(err)
}
}
- boxstickergenerate function
exports.boxstickergenerate = (current, doc, order, user) => {
doc.info['Title'] = `boxsticker${order.awbNumber}`
doc
.fillColor('black')
.rect(40, 75, 150, 30).fill()
.lineWidth(1.5)
.moveTo(40, 120)
.lineTo(560, 120).stroke()
doc
.fillColor('white')
.font('Helvetica-Bold')
.fontSize(20)
.text(order.service, 40, 80)
doc.fillColor('black')
.font('Helvetica-Bold')
.fontSize(11)
.text('FROM', 40, 140)
.font('Helvetica')
.text(order.consignor, 40, 155)
.text(`${order.consignorAddress1}, ${order.consignorAddress2}, ${order.consignorCity}, ${order.consignorState}, ${order.consignorPincode}`, 40, 170, {width: 350, align:'left'})
.font('Helvetica-Bold')
.text(order.origin, 40, 215)
.font('Helvetica')
.text(`TEL NO: ${order.consignorContactNumber}`, 40, 230)
.lineWidth(1.5)
.moveTo(40, 260)
.lineTo(560, 260).stroke()
.font('Helvetica-Bold')
.fontSize(16)
.text(`BOX NO ${current + 1}/${order.numberOfBoxes}`, 465, 140, {width: 100, align:'left'})
.rect(440, 160, 115, 30).fill()
.rect(440, 210, 115, 30).fill()
.fillColor('white')
.fontSize(11)
.text(order.client.username, 445, 165)
.text(order.service, 445, 215)
.fillColor('black')
.font('Helvetica-Bold')
.fontSize(16)
.text('TO', 40, 270)
.font('Helvetica')
.text(order.consignee, 40, 290)
.text(`${order.consigneeAddress1}, ${order.consigneeAddress2}, ${order.consigneeCity}, ${order.consigneeState}, ${order.consigneePincode}`, 40, 310, {width: 450, align:'left'})
.font('Helvetica-Bold')
.text(order.destination, 40, 370)
.font('Helvetica')
.text(`TEL NO: ${order.consigneeContactNumber}`, 40, 390)
.lineWidth(1.5)
.moveTo(40, 410)
.lineTo(560, 410).stroke()
.fontSize(14)
.text(`SHIPMENT DATE:`, 40, 430)
.text(moment(order.bookingDate).format(shortDateFormat), 160, 430)
.text(`SHIPMENT WEIGHT: ${order.chargeableWeight}`, 40, 450)
.text(`NO OF BOX: ${order.numberOfBoxes}`, 40, 470)
.text(`WAYBILL NO: ${order.awbNumber}`, 300, 450)
//.image(`box_${order.awbNumber}.png`, 265, 490, {width: 80, align:'center'})
.lineWidth(1.5)
.moveTo(40, 550)
.lineTo(560, 550).stroke()
.text('Office Purpose Only', 230, 570, {width: 150, align:'center'})
//.image(`box_${order.awbNumber}.png`, 265, 590, {width: 80, align:'center'})
.lineWidth(1.5)
.moveTo(40, 650)
.lineTo(560, 650).stroke()
.text(user.username, 230, 670, {width: 150, align:'center'})
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
你使用 pm2 和 --watch 吗?这实际上是我的问题,互联网上的所有事情都是为了增加 Nginx 配置文件中的超时,我尝试了一切,但我没有意识到问题是因为我正在上传文件,因此更改了进程,因此 pm2 将在发送我在前端期望的响应之前重新启动我的应用程序。我希望这能给你一个想法。
are you using pm2 with --watch? That was actually my issue, all the things around the internet is to increase your timeouts in the Nginx config file, I tried everything, and I didn't realized that the issue was because I was uploading a file, therefore changing a folder in the process, so pm2 will restart my app right before sending the response I was expecting in the front end. I hope this give you an idea.
我不知道你是否解决了你的问题,但我遇到了同样的问题,并找到了一种与上面不同的解决方案(但也可能是这个)。
我的问题来自于新服务器上不存在生成文件的子目录。
自从创建了子目录后,我就在本地计算机上工作了,我只是在创建文件所需的正确路径中创建了子目录,然后它就像一个魅力一样。
I don't know if you solved your problem or not but I had the same issue and found a solution that is not the same as above (but it could be this one too).
My problem was coming from the fact that the subdirectory where the file was generated didn't not exist on the new server.
Worked on my local machine since I had created the subdir, I simply created the subdirectory in the correct path that was needed to create the file and it worked like a charm afterwards.