It is required to receive requests from the required IP addresses at the link 127.0.0.1:3000/test in the get format on nodejs and get the json file. When sending a GET request, a 404 error is generated according to the code below
http.createServer((request, response) => {
console.log(request.url);
console.log(request.method);
console.log(request.headers);
console.log(request.socket.remoteAddress);
if (request.method === "GET") {
console.log(`Requested address: ${request.url}`);
const filePath = request.url.substr(1);
fs.access(filePath, fs.constants.R_OK, err => {
if (err) {
response.statusCode = 404;
response.end("Resourse not found!");
} else {
fs.createReadStream(filePath).pipe(response);
}
});
} else {
console.log(`Requested address: ${request.url}`);
}
}).listen(3000, function() {
console.log("Server started at 3000");
});
I would suggest using express.
const app = require('express')();
const fs = require('fs');
app.get('/test', (request, response), async () => {
fs.createReadStream('./test.json').pipe(response);
});
app.listen(3000);
Or if you're looking for a more dynamic approach.
app.get('/:filePath', (request, response), async () => {
const { filePath } = req.params;
fs.access(filePath, fs.constants.R_OK, err => {
if (err) {
res.status(404).send('Resourse not found!');
} else {
fs.createReadStream(filePath).pipe(response);
}
});
});
Related
I am trying to make a proxy server in Node.js which can block URLs based off of a Regex expression and also has basic authentication, to be used as a proxy with IOS devices.
Here is my current code:
let http = require('http');
let net = require('net');
let httpProxy = require('http-proxy');
let url = require('url');
let fs = require('fs');
let auth = require('basic-auth');
const port = process.env.PORT || 8080;
let proxy = httpProxy.createServer();
let blacklist = [/.*example\.com$/];
function inBlacklist(url) {
return blacklist.some(function (blacklistItem) {
return blacklistItem.test(url);
});
}
let logStream = fs.createWriteStream('log.txt', { flags: 'a' });
console.log("Booting Up | Port", port);
let allowedCredentials = [
'root:root'
]
function check (username, password) {
if (username && password) {
if(allowedCredentials.indexOf(`${username}:${password}`) > -1){
return true;
} else return false;
} else {
return false;
}
};
var server = http.createServer(function (req, res) {
var credentials = auth(req);
if (!credentials || !check(credentials.name, credentials.pass)) {
res.statusCode = 401
res.setHeader('WWW-Authenticate', 'Basic realm="Please log in using your given username and password."')
return res.end('Access denied');
} else {
res.end('Access granted')
}
var serverUrl;
try { serverUrl = url.parse(req.url); }
catch { console.log(0); return; }
var shouldBlock = false;
try { shouldBlock = inBlacklist(serverUrl.hostname); } catch {
console.log(1); return;
}
logStream.write(`CONNECT1: ${req.url}\nHOSTNAME: ${serverUrl.hostname}\nshouldBlock: ${shouldBlock}\nreqURL: ${req.url}\n---------\n`);
if (shouldBlock) {
try {
return proxy.web(req, res, { target: '0.0.0.0' }, function () {
res.writeHead(404);
res.end('Not found.');
});
} catch { console.log(3); return; }
}
try { proxy.web(req, res, { target: req.url, secure: false }, function (e) { console.log("Proxy.web Accept Error"); res.writeHead(404); res.end('Not found. (P.W. Accept Error)'); }); } catch { console.log(2); }
}).listen(port, '0.0.0.0', () => {
console.log("Listening at: http://example.com:" + port);
});
server.on('listening', () => {
console.log(`Server is listening on port ${server.address().port}`);
});
server.on('close', function () {
logStream.write('server closed\n');
logStream.end();
});
server.on('error', function (err) {
logStream.write(`ERROR: ${err}\n---------\n`);
console.log('Server error:', err);
});
server.on('connect', function (req, socket) {
var reqport = req.url.split(':')[1];
var serverUrl;
if (reqport == 443) {
try { serverUrl = url.parse("https://" + req.url); }
catch (err) { console.log(err); return; }
} else if (reqport == 80) {
try { serverUrl = url.parse("http://" + req.url); }
catch (err) { console.log(err); return; }
} else return;
var shouldBlock = false;
try { shouldBlock = inBlacklist(serverUrl.hostname); } catch {
console.log(1); return;
}
logStream.write(`CONNECT2: ${req.url}\nHOSTNAME: ${serverUrl.hostname}\nshouldBlock: ${shouldBlock}\nreqURL: ${req.url}\n---------\n`);
if (shouldBlock) {
try {
socket.write('HTTP/1.1 404 Not Found\r\n' +
'\r\nNot found.');
}
catch { console.log("Caught error"); }
return socket.end();
}
var srvSocket = net.connect(serverUrl.port, serverUrl.hostname, function () {
try {
socket.write('HTTP/1.1 200 Connection Established\r\n' +
'Proxy-agent: Node-Proxy\r\n' +
'\r\n');
} catch {
logStream.write(`ERROR WRITING\n---------\n`);
}
srvSocket.pipe(socket).on('error', (err) => {});
socket.pipe(srvSocket).on('error', (err) => {});
}).on('error', (err) => err);
});
Is there any better way to do this? I am getting frequent errors with the srvSocket socket disconnecting.
Most importantly, the authentication doesn't work. For some devices, no authentication is required in the IOS settings, while on others authentication is required but doesn't matter what username and password are inputted.
Why does this happen?
I have been working on this issue for 2 days, looked at various pages and cannot find a single solution that would work.
Please only reply if you know how to write them with async await functions and please reply if you know the answer of fetch api. I am not looking for axios solutions for the time being.
I have a backend server which runs on port 8000 of localhost, frontend runs on port 3000. Front end is written in React, backend is written in Node/Express.
I am able to successfully make a GET request from backend server but the POST request fails for some reason with the error "VM942:1 POST http://localhost:8000/frontend-to-backend 500 (Internal Server Error)"
Backend server has this error: SyntaxError: Unexpected token u in JSON at position 0
at JSON.parse ()
// React-To-Node-Connection
// React "App.js" file
// "package.json" file contains this
// "proxy": "http://localhost:8000"
useEffect(() => {
const getBackend = async () => {
const res = await fetch('backend-to-frontend');
const data = await res.json();
if (!res.ok) {
throw new Error(`Cannot get data from backend server. HTTP Status: ${res.status}`);
}
console.log(data.message);
// Prints "Hi from backend!"
}
getBackend();
const postBackend = async () => {
try {
const res = await fetch('http://localhost:8000/frontend-to-backend',
{
method: 'POST',
mode: 'no-cors',
body: JSON.stringify({ message: 'Hi from frontend!' }),
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
}
}
);
if (res.ok) {
const data = await res.json();
console.log(data);
}
} catch (error) {
console.error(error);
}
}
postBackend();
}, []);
Now the backend code:
app.get('/backend-to-frontend', (req, res) => {
res.json({ message: 'Hi from backend!' });
});
app.post('/frontend-to-backend', (req, res) => {
try {
const reactMessage = JSON.parse(req.body.data);
console.log(`message: ${reactMessage}`);
} catch (err) {
console.error(err);
}
});
How to fix this? Please help!
Full backend server code can be found here:
const express = require("express");
const app = express();
app.use(express.urlencoded({ extended: true }));
app.get('/backend-to-frontend', (req, res) => {
res.json({ message: 'Hi from backend!' });
});
app.post('/frontend-to-backend', (req, res) => {
try {
const reactMessage = JSON.parse(req.body.data);
console.log(`message: ${reactMessage}`);
} catch (err) {
console.error(err);
}
});
const port = process.env.PORT || 8000;
app.listen(port, function () {
console.log(`Backend server started on port ${port}.`);
});
with no-cors, you can only use simple headers, so you cannot POST JSON (see: Supplying request options)
Try urlencoded:
const postBackend = async() => {
try {
const res = await fetch('http://localhost:8000/frontend-to-backend', {
method: 'POST',
mode: 'no-cors',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
body: new URLSearchParams({
'message': 'Hi from frontend!'
})
});
if (res.ok) {
const data = await res.json();
console.log(data);
}
} catch (error) {
console.error(error);
}
}
postBackend();
and on the server, don't parse req.body, as it's already done by middleware:
app.post('/frontend-to-backend', (req, res) => {
console.log('req.body: ', req.body);
try {
const reactMessage = req.body.message;
req.body.data may be an object (check with debugger). If so, you might try to stringify before parsing :
JSON.parse(JSON.stringify(req.body.data))
I finally found the answer, here is my sample code. I did not change the React code that much so it is pretty much same, I removed the no cors section and added cors to Express JS code.
Here is my React code.
// React-To-Node-Connection
// "package.json" file has the following line
// "proxy": "http://localhost:8000"
// React Code
useEffect(() => {
const getBackend = async () => {
const res = await fetch('/backend-to-frontend');
const data = await res.json();
if (!res.ok) {
throw new Error(`Cannot get data from backend server. HTTP Status: ${res.status}`);
}
console.log(data.message);
}
getBackend();
const postBackend = async () => {
try {
await fetch('http://localhost:8000/frontend-to-backend',
{
method: 'POST',
body: JSON.stringify({ message: 'Hi from frontend!' }),
headers: {
'Content-Type': 'application/json'
}
}
);
} catch (err) {
console.error(err);
}
}
postBackend();
}, []);
And here is my Express JS code.
const express = require("express");
const app = express();
app.use(express.urlencoded({ extended: true }));
// Express JS Code
const cors = require('cors');
app.use(express.json());
app.use(cors());
app.get('/backend-to-frontend', (req, res) => {
res.json({ message: 'Hi from backend!' });
});
app.post('/frontend-to-backend', (req, res) => {
try {
console.log(req.body.message);
} catch (err) {
console.error(err);
}
});
const port = process.env.PORT || 8000;
app.listen(port, function () {
console.log(`Backend server started on port ${port}.`);
});
Thanks.
I am new to Node JS. Please help me to understand what am I doing wrong in the POST request. Sometimes my POST request is getting successfully resolved but sometimes it is giving me ECONNRESET.
I am sharing my app.js and file reader wrapper module.
GET is working perfectly fine.
Below is my App.js
const express = require('express');
const FileReader = require('./readFS');
const app = express();
const FS = new FileReader();
const port = 3000;
app.listen(3000, '127.0.0.1', () => {
console.log(`App running on port ${port}`);
});
app.use(express.json());
app.get('/api/v1/tours', (request, response) => {
const data = FS.read(`${__dirname}/dev-data/data/tours-simple.json`).then(
(data) => {
response.status(200).json({
status: 'success',
results: data.length,
data: {
tours: data,
},
});
}
);
});
app.post('/api/v1/tours', (request, response) => {
(async (req, res) => {
const tours = await FS.read(`${__dirname}/dev-data/data/tours-simple.json`);
const newID = tours[tours.length - 1].id + 1;
const newTour = Object.assign({ id: newID }, req.body);
tours.push(newTour);
console.log('File written Started');
await FS.write(
`${__dirname}/dev-data/data/tours-simple.json`,
JSON.stringify(tours)
);
console.log('File written Successfully');
res.status(200).send('Created Succesfully');
})(request, response);
});
File Reader Module:
module.exports = class {
constructor() {
this.tours = [];
}
read(path) {
return new Promise((resolve, reject) => {
if (this.tours.length > 0) {
resolve(this.tours);
}
fs.readFile(path, 'utf-8', (err, data) => {
if (err) reject(er);
this.tours = Object.assign(JSON.parse(data));
resolve(this.tours);
});
});
}
write(path, data) {
return new Promise((resolve, reject) => {
if (data.length <= 0) reject('Data is empty');
fs.writeFile(path, data, (err) => {
if (err) reject('Could not write');
resolve('Done');
});
});
}
};
Explanation of the error I was encountering
My issue with occasionally receiving ECONNRESET when POSTing to my listening endpoint was caused by the endpoint automatically restarting after each successful POST of a file to that same endpoint.
I have a small issue with mongoose, what I am doing is getting data from online rss feeds, parsing it, and passing it to an array, from which I feed a mongoose model, and all this happens in the get route, what I want to accomplish is delete all the data first from the mongoose model and then populate it with the new data, but it always either deletes the data all together, since the parser iterates a few times, or it doesn't delete anything and the data just keeps adding to the model.
Here's my code
'use strict';
const Promise = require('bluebird');
const request = require('request');
const FeedParser = require('feedparser');
const express = require('express');
const router = express.Router();
const xray = require('x-ray')();
var Post = require('../models/post');
var dataArray = [];
router.get('/', function (req, res) {
const fetch = (url) => {
return new Promise((resolve, reject) => {
if (!url) {
return reject(new Error(`Bad URL (url: ${url}`));
}
const feedparser = new FeedParser();
const items = [];
feedparser.on('error', (e) => {
return reject(e);
}).on('readable', () => {
// This is where the action is!
var item;
console.time('loading')
while (item = feedparser.read()) {
items.push(item);
}
}).on('end', () => {
resolve({
meta: feedparser.meta,
records: items
});
});
request({
method: 'GET',
url: url
}, (e, res, body) => {
if (e) {
return reject(e);
} else if (res.statusCode != 200) {
return reject(new Error(`Bad status code (status: ${res.statusCode}, url: ${url})`));
}
feedparser.end(body);
feedparser.on('end', function () {
console.log('Done');
});
});
});
};
Promise.map([
'url',
'url',
'url',
'url'], (url) => fetch(url), { concurrency: 4 }) // note that concurrency limit
.then((feeds) => {
feeds.forEach(feed => {
feed.records.forEach(record => {
dataArray.push(record);
});
});
}).catch(function (error) {
console.log(error);
});
Post.remove({}, function (err) {
if (err) {
console.log(err);
} else {
console.log('collection removed');
}
});
dataArray.forEach(post => {
Post.create({
title: post.title,
content: post.description,
created: post.date,
image: post['rss:image']['#'],
link: post.link
}, function (err, newPost) {
console.log(newPost.title);
});
});
Post.find({}, function (err, posts) {
if (err) {
console.log(err);
} else {
res.render('index/home', {
posts: posts
});
}
});
});
module.exports = router;
None of this is going to run synchronously. You can do Something like this :
'use strict';
const Promise = require('bluebird');
const request = require('request');
const FeedParser = require('feedparser');
const express = require('express');
const router = express.Router();
const xray = require('x-ray')();
var Post = require('../models/post');
var dataArray = [];
const fetch;
router.get('/', function (req, res) {
Post.remove({}, function (err) {
if (err) {
console.log(err);
} else {
console.log('collection removed. Starting to fetch Posts from Service');
fetch = (url) => {
return new Promise((resolve, reject) => {
if (!url) {
return reject(new Error(`Bad URL (url: ${url}`));
}
const feedparser = new FeedParser();
const items = [];
feedparser.on('error', (e) => {
return reject(e);
}).on('readable', () => {
// This is where the action is!
var item;
console.time('loading')
while (item = feedparser.read()) {
items.push(item);
}
}).on('end', () => {
resolve({
meta: feedparser.meta,
records: items
});
});
request({
method: 'GET',
url: url
}, (e, res, body) => {
if (e) {
return reject(e);
} else if (res.statusCode != 200) {
return reject(new Error(`Bad status code (status: ${res.statusCode}, url: ${url})`));
}
feedparser.end(body);
feedparser.on('end', function () {
console.log('Done');
});
});
});
};
}
});
Promise.map([
'url',
'url',
'url',
'url'], (url) => fetch(url), { concurrency: 4 }) // note that concurrency limit
.then((feeds) => {
feeds.forEach(feed => {
dataArray = dataArray.concat(feed.records);
/*feed.records.forEach(record => {
dataArray.push(record);
});*/
});
console.log('inserting posts in the collection');
dataArray.forEach(post => {
Post.create({
title: post.title,
content: post.description,
created: post.date,
image: post['rss:image']['#'],
link: post.link
}, function (err, newPost) {
console.log(newPost.title);
});
});
console.log("Fetching posts from the collection");
Post.find({}, function (err, posts) {
if (err) {
console.log(err);
} else {
res.render('index/home', {
posts: posts
});
}
});
}).catch(function (error) {
console.log(error);
});
});
module.exports = router;
I haven't tested this. Please test it on your end. Let me know if there's an error or something.
I've set up a NodeJS server which can be accessed by a client. Every once in a while it's necessary to let the server connect to a second server and feed the information retrieved back to the client.
Connecting to the second server is the easy part, but to be honest I have no idea how to send it back to the client. res.write seems to be forbidden during the connection with the second server.
The connection from the client is handled by handleGetRequest. The connection with the second server starts at http.get.
var http = require('http');
var url = require('url');
var server = http.createServer(function(req, res) {
var url_parsed = url.parse(req.url, true);
if (req.method ==='GET') {
handleGetRequest(res, url_parsed);
} else {
res.end('Method not supported');
}
});
handleGetRequest = function(res, url_parsed) {
if (url_parsed.path == '/secondary') {
var OPTIONS = {
hostname: "localhost",
port: "8900",
path: "/from_primary"
}
http.get(OPTIONS, function(secget) {
resget.on('data', function(chunk) {
// either store 'chunk' for later use or send directly
});
}).on('error', function(e) {
console.log("Error " + e.message);
});
} else {
res.writeHead(404);
}
res.end('Closed');
};
server.listen(8000);
How do I send the chunk from http.request to the client?
I thinks passing the callback to the handleGetRequest will fix this issue:
if (req.method === 'GET') {
handleGetRequest(url_parsed, function (err, response) {
if (err) {
return res.sendStatus(500);
}
res.json(response);
});
} else {
res.end('Method not supported');
}
handleGetRequest = function (url_parsed, callback) {
// OPTIONS ...
http.get(OPTIONS, function(resget) {
var data = '';
resget.on('data', function(chunk) {
data += chunk;
});
resget.on('end', function() {
callback(null, data);
});
}).on('error', function(e) {
callback(e);
});
}
Thanks to #TalgatMedetbekov for the suggestions. I managed to implement it like this:
var http = require('http');
var url = require('url');
var server = http.createServer(function(req, res) {
var url_parsed = url.parse(req.url, true);
if (req.method ==='GET') {
handleGetRequest(res, url_parsed);
} else {
res.end('Method not supported');
}
});
handleGetSecondaryRequest = function(callback, res) {
var OPTIONS = {
hostname: "localhost",
port: "8900",
path: "/from_primary"
}
var data = null;
http.get(OPTIONS, function(func, data) {
func.on('data', function(chunk) {
data += chunk;
});
func.on('end', function() {
callback(res, data);
});
}).on('error', function(e) {
callback(res, e);
})
};
var secReqCallback = function(res, recData)
{
res.write(recData);
res.end("END");
};
handleGetRequest = function(res, url_parsed) {
if (url_parsed.path == '/secondary') {
handleGetSecondaryRequest(secReqCallback, res);
} else {
res.writeHead(404);
}
};
server.listen(8000);
It works, kind of. There's an 'undefined' in front of the string which I can't find the cause for, but the basic functionality works perfect.
The callback construction is necessary to synchronize the asynchronous nature of NodeJS.