so, after trying a few times, it is clear that I am doing something wrong but I do not realize what. My steps are:
rm -rf .next/ && npm run build
upload .next, package.json,next.config.js and server.js to cPanel file manager
create node JS app from cPanel with 14.18.3 version. (on my local node -v show me 14.18.1, but on cPanel I don't have this version)
run npm install with success
then i'm geting 503 service unavailable.
server.js
// server.js
const { createServer } = require('http');
const { parse } = require('url');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const hostname = 'localhost';
const port = process.env.PORT || 3000;
// when using middleware `hostname` and `port` must be provided below
const app = next({ dev, hostname, port });
const handle = app.getRequestHandler();
app.prepare().then(() => {
createServer(async (req, res) => {
try {
// Be sure to pass `true` as the second argument to `url.parse`.
// This tells it to parse the query portion of the URL.
const parsedUrl = parse(req.url, true);
const { pathname, query } = parsedUrl;
if (pathname === '/a') {
await app.render(req, res, '/a', query);
} else if (pathname === '/b') {
await app.render(req, res, '/b', query);
} else {
await handle(req, res, parsedUrl);
}
} catch (err) {
console.error('Error occurred handling', req.url, err);
res.statusCode = 500;
res.end('internal server error');
}
}).listen(port, (err) => {
if (err) throw err;
console.log(`> Ready on http://${hostname}:${port}`);
});
});
package.json scripts
"scripts": {
"dev": "node server.js",
"build": "next build",
"start": "NODE_ENV=production node server.js"
},
next.config.json
/** #type {import('next').NextConfig} */
const nextConfig = {
basePath: '/apps/nextjs-cpanel',
trailingSlash: true,
reactStrictMode: true,
sassOptions: {
additionalData: `#import "./styles/variables.scss"; #import "./styles/mixins.scss";`,
}
};
module.exports = nextConfig;
on cPanel application root is apps/nextjs-cpanel, application url is my-domain/apps/nextjs-cpanel and application startup file server.js
Related
i have static app with nextJs 13 without any api data or database in my local machine it work normal ,but in production server with cpanel i have 503 error with this log
node:events:491
throw er; // Unhandled 'error' event
^
Error: read EINVAL
at Pipe.onStreamRead (node:internal/stream_base_commons:217:20)
Emitted 'error' event on Socket instance at:
at emitErrorNT (node:internal/streams/destroy:157:8)
at emitErrorCloseNT (node:internal/streams/destroy:122:3)
at processTicksAndRejections (node:internal/process/task_queues:83:21) {
errno: -22,
code: 'EINVAL',
syscall: 'read'
}
I followed the documentation steps and i change scripts start and i add my custom server also
package.json
"scripts": {
"dev": "node server.js",
"build": "next build",
"start": "NODE_ENV=production node server.js"
},
server.js
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const dev = process.env.NODE_ENV !== 'production'
const hostname = 'localhost'
const port = 3000
// when using middleware `hostname` and `port` must be provided below
const app = next({ dev, hostname, port })
const handle = app.getRequestHandler()
app.prepare().then(() => {
createServer(async (req, res) => {
try {
// Be sure to pass `true` as the second argument to `url.parse`.
// This tells it to parse the query portion of the URL.
const parsedUrl = parse(req.url, true)
const { pathname, query } = parsedUrl
if (pathname === '/a') {
await app.render(req, res, '/a', query)
} else if (pathname === '/b') {
await app.render(req, res, '/b', query)
} else {
await handle(req, res, parsedUrl)
}
} catch (err) {
console.error('Error occurred handling', req.url, err)
res.statusCode = 500
res.end('internal server error')
}
}).listen(port, (err) => {
if (err) throw err
console.log(`> Ready on http://${hostname}:${port}`)
})
})
Before uploading my code to Heroku, my API calls worked just fine. However, it returns a status code of 503 (Service Unavailable) after deployment.
This is my code
app.js file in my root folder (server file)
mongoose.connect(process.env.MONGO_URI, { useNewUrlParser: true, useUnifiedTopology: true }).then(() => console.log("Connected to db!")).catch(dbErr => console.log(dbErr));
app.use(express.json());
app.use(cors());
app.post("/post-result", async (req, res) => {
console.log(req.body.val);
const newSurvey = new survey({ surveyValues: req.body.val });
await newSurvey.save()
.then(data => {
res.send(newSurvey);
console.log(newSurvey);
}).catch(err => console.log(err));
});
app.get("/results", async (req, res) => {
const result = await survey.find({});
res.send(result);
});
if (process.env.NODE_ENV === "production") {
app.use(express.static(path.join(__dirname, "/client/build")));
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname, "client", "build", "index.html"));
})
} else {
app.get("/", (req, res) => {
res.send("API running");
})
}
app.listen(process.env.PORT, () => console.log("Listening on PORT 8080"));
My react file, where the API calls were made
const handleFormSubmit = async (e, val) => {
const { data } = await Axios.post("/post-result", { val });
}
package.json file
{
"scripts": {
"start": "nodemon app.js",
"heroku-postbuild": "NPM_CONFIG_PRODUCTION=false npm install --prefix client && npm run build --prefix client"
},
"dependencies": {
"cors": "^2.8.5",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"mongoose": "^6.0.12"
}
}
Error log in the console
Uncaught (in promise) Error: Request failed with status code 503 at e.exports createError.js:16) at e.exports (settle.js:17) at XMLHttpRequest.S (xhr.js:66)
Option 1 :
Maybe you should try using all the url instead of Axios.post("/post-result",{..}) You can use local variable to determine if you are in Prod or in local environment, create in util folder a file called for example baseUrl.js :
const baseUrl = process.env.NODE_ENV === "production"
? "https://[your url used in port]"
: "http://localhost:[your port]";
export default baseUrl;
And then import baseUrl in your folder and replace your Axios request by :
const { data } = await Axios.post(baseUrl + "/post-result", { val });
Option 2 :
Also I noticed that you don't allow any URL in Cors Options :
let corsOptions = {
origin: ["URL ALLOWED", ...],
};
app.use(cors(corsOptions));
We're using Nextjs/Reactjs as our FE and we have a server.js file that will allow us to upload image on public/images/uploads but for some reason whenever we run the server we are getting error Cannot GET /
Here is the code we have on server.js
const { createServer } = require('http');
const { parse } = require('url');
const next = require('next');
const express = require('express');
const multer = require('multer');
const cors = require('cors');
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
var app = next({ dev });
const handle = app.getRequestHandler();
const appExpress = express();
app.prepare().then(() => {
createServer((req, res) => {
const parsedUrl = parse(req.url, true)
const { pathname, query } = parsedUrl
if (pathname === '/a') {
app.render(req, res, '/a', query)
} else if (pathname === '/b') {
app.render(req, res, '/b', query)
} else {
handle(req, res, parsedUrl)
}
}).listen(port, err => {
if (err) throw err
console.log(`> Ready on http://localhost:${port}`)
})
})
appExpress.use(express.static('public'))
let storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'public/images/uploads')
},
filename: (req, file, cb) => {
cb(null, Date.now() + '-' + file.originalname)
}
});
const upload = multer({ storage })
appExpress.use(cors());
appExpress.post('/upload', upload.single('image'), (req, res) => {
if (req.file)
res.json({
imageUrl: `images/uploads/${req.file.filename}`
});
else
res.status("409").json("No Files to Upload.");
});
const PORT = 5000;
appExpress.listen(PORT);
console.log('api running on port: ' + PORT);
These are the scripts include on our package.json
"dev": "next",
"build": "next build && next export",
"start": "next start",
"server": "node server.js"
},
Hoping to get some answers and recommendations. This codes are working locally without any issues
You need to add a route for the GET / like this:
appExpress.get('/', (req, res) => {
res.json({server: 'Running..!'});
});
Bizarre situation going on here with my websocket. It's giving me the error
Error during WebSocket handshake: Unexpected response code: 200
Which for the life of me I cannot figure out why.
I've set up a very similar server with the exact same code with the exact same servers & settings. The only difference is one server has a .com TLD while the other has a .sg TLD.
I've reduced it down to the simplest form, which is the below and the error is still happening. It's on the api side for sure and not the frontend as the frontend can connect to the .com TLD.
Below is all the code that I believe is related to the problem. If you think there might be other areas please ask and I will post other areas. It's hosted on AWS Elastic Beanstalk. I've also set the SSL cert to domain.com & *.domain.com
Does anybody know why this might be happening?
The bizarre thing to me is I literally set up a server with these exact settings and it's working perfectly fine.
server.js (start point in package.json)
'use strict';
(async function() {
// Server Setup
const WSServer = require('ws').Server;
const app = await require('./app.js');
const server = require('http').createServer(app);
const port = 3075;
// Create web socket server on top of a regular http server
const wss = new WSServer({
server: server
});
// Also mount the app here
// server.on('request', app);
let sendMessage = {
"connected":"connected to web socket",
}
wss.on('connection', function connection(ws) {
ws.send(JSON.stringify(sendMessage));
ws.on('message', async function incoming(message) {
let interval = setInterval(async () => {
console.log("ping");
ws.send(message);
}, 500);
});
ws.on('close', function close() {
console.log('/socket connection Closed');
});
});
server.listen(process.env.PORT || port, function() {
console.log(`AppName https/wss is listening on port ${process.env.PORT || port}`);
});
})();
app.js (removed much of the code that is irrelevant to this question)
module.exports = (async function() {
const {Config,Environments} = await require("./common/config");
const packageJson = require('./package.json');
// Handler
const AuthFunc = await require("./funcs/user/auth");
const BillingFunc = await require("./funcs/billing/billing");
const ObjectUtil = require("./utils/object");
const AccountStatusEnum = require("./enums/account-status").accountStatusEnum;
const sleep = require('util').promisify(setTimeout);
const {t} = require('./translations/i18n').i18n;
const {availableLanguages} = require('./translations/all');
// Simulate real API calls
const delayResponse = 250;// milliseconds
// ==============================================
// Base setup
// ==============================================
process.env.TZ = "Etc/GMT"
const express = require('express');
const app = express();
var expressWs = require('express-ws')(app);
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(require('express-useragent').express());
// Cors
app.use(async function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, auth-id, auth-token, x-csrf-token, _csrf");
res.header('Access-Control-Allow-Methods', 'PATCH, POST, GET, DELETE, OPTIONS');
next();
});
// ==============================================
// Auth
// ==============================================
const normRoute = (req, res, next) => {
req.body = (req.body != undefined && req.body != null) ? ObjectUtil.toCamelCaseKeys(req.body) : req.body;
response(req,res,next(req));
}
// Does not need to be logged in but passes user info if logged in
const passRoute = async (req, res, next) => {
authRoute(req, res, next, AccountStatusEnum.any, true);
}
const authRoute = async (req, res, next, minimumStatus, passRoute) => {
req.body = (req.body != undefined && req.body != null) ? ObjectUtil.toCamelCaseKeys(req.body) : req.body;
let authId = (req.headers['auth-id'] !== undefined) ? req.headers['auth-id'] :"";
let authToken = (req.headers['auth-token'] !== undefined) ? req.headers['auth-token'] : "";
let r = await AuthFunc.authUser(
req,
req.ip,
req.useragent,
authId,
authToken,
minimumStatus,
);
if(r.err.code){
if(r.err.authError && passRoute){
response(req,res,next(req,null));
return false;
}else{
response(req,res,r);
return false;
}
}
let user = r.res.user;
r = await BillingFunc.updateSubStatus(req,user);
if(r.err.code){ response(req,res,r); return false; }
if(r.res.userStatus !== undefined){
user.status = r.res.userStatus;
}
response(req,res,next(req,user));
}
// ===============================================================
// Routes
// ===============================================================
app.get('/', function(req, res) {
res.send(
'<html>'+
'<head></head>'+
'<body>'+
'API is running <br>'+
'App: '+Config.FrontEnd.AppName+'<br>'+
'Env: '+Config.Env+'<br>'+
'Version: '+packageJson.version+'<br>'+
'</body>'+
'</html>'
);
});
// ==============================================
// Response type
// ==============================================
const response = async (req,res,obj) => {
await obj;
Promise.resolve(obj).then(function(val) {
if(delayResponse >= 1 && (Config.Env === Environments.Local)){
setTimeout(function(){
resume(req,res,val);
}, delayResponse);
return true;
}
resume(req,res,val);
});
}
const resume = (req,res,obj) => {
obj = (obj === undefined) ? {} : obj;
var status = (obj.status !== undefined) ? obj.status : 200;
// Let status override settings
if(obj.status === undefined){
if((obj.err.code)){
status = 400;
}else if(obj.res === undefined || ObjectUtil.isEmpty(obj.res)){
// status = 204;
}
}
let json = {};
json.err = obj.err;
json.res = obj.res;
json = ObjectUtil.toCamelCaseKeys(json);
res.status(status).json(json);
}
// ==============================================
// Return the app
// ==============================================
return app;
})();
package.json
{
"name": "name-api",
"version": "1.17.0",
"description": "name-api",
"main": "server.js",
"dependencies": {
"axios": "^0.21.1",
"cookie-parser": "^1.4.4",
"express": "^4.17.1",
"express-session": "^1.17.1",
"express-useragent": "^1.0.13",
"express-ws": "^4.0.0",
"googleapis": "^50.0.0",
"mocha": "^8.0.1",
"mysql": "github:mysqljs/mysql",
"nodemailer": "^6.4.6",
"query-string": "^6.12.1",
"stripe": "^8.60.0",
"ws": "^7.4.3"
},
"devDependencies": {},
"scripts": {
"test": "mocha",
"start": "node server.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/..."
},
"author": "",
"license": "ISC",
"bugs": {
"url": "https://github.com/..."
},
"homepage": "https://github.com/..."
}
Problem solved.
It was a load balancer issue. Apparently this doesn't work well with Classic Load Balancer. I believe it's due to the way it's requested.
Changing over to a Application Load balancer fixed the issue for me.
I have a NextJS project hosted on Vercel
I have added server.js file to use custom express server that will 301 redirect some urls
when I run it locally the re-directions work but when I push the code to production on Vercel the re-directions doesn't work
This is the server.js file:
const express = require('express')
const next = require('next')
const bodyParser = require('body-parser')
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
app.prepare().then(() => {
const server = express()
server.use(bodyParser.json())
//Redirect to main page
server.get(
[
'/product-tag/885-m2/?orderby=menu_order',
'/product-tag/885-m2/?orderby=price',
'/cutter/mwhzt-zvvit/mwhzt-zvvit-2.html?___store=default&___from_store=english',
'/sales/guest/form/'
]
, (req, res) => {
res.redirect(301, '/')
})
server.get('*', (req, res) => {
return handle(req, res)
})
server.listen(3000, (err) => {
if (err) throw err
console.log('> Read on http://localhost:3000')
})
})
and this is my package.json scripts section:
"scripts": {
"dev": "node --inspect server.js",
"build": "next build",
"start": "NODE_ENV=production node server.js",
},
The urls generally do not contain the query params i.e the part after "?" in the request. Try this instead.
server.get('*', (req, res) => {
const redirectUrls = [
'/product-tag/885-m2/?orderby=menu_order',
'/product-tag/885-m2/?orderby=price',
'/cutter/mwhzt-zvvit/mwhzt-zvvit-2.html?___store=default&___from_store=english',
'/sales/guest/form/'
];
if (redirectUrls.includes(req.url)) {
res.redirect(301, '/');
}
next();
})
Also make sure you write it above
server.get('*', (req, res) => {
return handle(req, res)
})
otherwise, the code will never run.