How can I use the new URL API to get request details? - node.js

After following a tutorial on Node.js I tried to get the details of a request like so:
const url = require('url');
http
.createServer((req, res) => {
*let parsedUrl = url.parse(req.url, true);*
res.write('----------> ');
res.write(parsedUrl.search);
res.write(parsedUrl.search);
re.write(parsedUrl.pathname);
res.write(' <----------');
res.end();
})
.listen(3000, () => cl('Listening on port 3000.'));
This is working fine but I get a warning that url.parse() is deprecated and instead I should use new URL() API. But the problem is that with url.parse() I can pass the req.url as parameter whereas with new URL() I have to pass a string as parameter, therefore I can't use req.url to get the request details. Or is something I'm missing?
http
.createServer((req, res) => {
*let myUrl = new URL(req.url.toString());*
res.write(myUrl);
res.end();
})
.listen(3000, () => cl('Listening on port 3000.'));
If curl this URL curl http://localhost:3000/test?hello=world, I get this error TypeError [ERR_INVALID_URL]: Invalid URL: /test?hello=world

import http from "node:http"
import { URL } from "node:url"
const PORT = 3000
const server = http.createServer((req, res) => {
const url = new URL(`http://${req.headers.host}${req.url}`)
return res.end(url.href)
})
server.listen(PORT, () => `Server is running on port ${PORT}`)

Related

GET request from local server using live-server

I am trying to fetch data from my local server and here is my server and how I handled GET requests:
const express = require('express');
const app = express();
const port = 3000;
app.use(express.json());
app.listen(port, () => {
console.log(`app running on port: ${port}...`);
});
const responseToClient = (req, res) => {
res.status(200).json({
status: 'success',
body: 'Hello from the server!',
});
};
app.get('/api', responseToClient);
When I run my server and send a GET request to this address: 127.0.0.1:3000/api with Postman, it works perfectly.
The thing is I created a html page along with a js file and want to fetch data from my local server by it. Here is my fetch request on my js file:
const url = '/api';
const fetchData = async () => {
try {
const response = await fetch(url);
const body = await response.json();
alert(body);
} catch (error) {
alert(error);
}
};
fetchData();
I run my html file with live-server (extension) which runs on port 5500 by default , so the address my fetch request goes to will be 127.0.0.1:5500/api (instead of 127.0.0.1:3000/api), so it does not exists and I get an error message.
I tried to change the port of my server and set it to 5500 (the same as live-server) but it did not work.
How can I run my local server and send requests to it with live-server and my html file?
Solved by using:
const url = 'http://localhost:3000/api';
instead of the ip address and installing cors middle ware.
If you do not want to have the HTML and JS files static-ed onto your Express server, then try this:
const url = '/api'; // bad
const url = '127.0.0.1:3000/api'; // better

URL as query param in proxy, how to navigate?

I'm using http-proxy to create a simple proxy: localhost:3000?q=${encodeURIComponent(targetURL)} will access targetURL using the proxy.
Here's my working code:
var http = require("http");
var httpProxy = require("http-proxy");
//create a server object:
http
.createServer(function (req, res) {
try {
// Get the `?q=` query param.
const url = req.query.q;
const parsed = new URL(decodeURIComponents(url));
const proxy = httpProxy.createProxyServer();
// Fix URLs and query params forwarding.
// https://stackoverflow.com/questions/55285448/node-http-proxy-how-to-pass-new-query-parameters-to-initial-request
proxy.on("proxyReq", function (proxyReq) {
proxyReq.path = parsed.toString();
});
proxy.on("end", () => res.end());
// Avoid the following error:
// "Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames"
req.headers["host"] = parsed.host || undefined;
proxy.web(req, res, { target: url }, (err) => {
throw err;
});
} catch (err) {
res.write(JSON.stringify({ error: err.message }));
res.end();
}
})
.listen(8080); //the server object listens on port 8080
When I visit localhost:3000?q=https://google.com, everything works. However, if I click on a link in the website, then the route is changed on my hostname directly, not in the query param.
So:
I go to localhost:3000?q=https://google.com
I click on "Images', which should bring me to localhost:3000?q=https://google.com/images
instead, it brings me to localhost:3000/images?q=https://google.com, which 404s
How do I solve navigation in the target website?

Node.js + React: How to POST

Follow on from this question: Axios can GET but not POST to the same URL
I've been trying to figure this out for too long now.
I want to POST from my React app to a .JSON file. Can anyone tell me what I'm doing wrong?
My AJAX POST function using axios always returns a 404. I'm listening for it on the node server but app.post never fires.
Thanks.
POST request from my React app:
postJson = (postJsonData) => {
axios.post('./postJson/', {
postJsonData
})
.then(function (response) {
console.log("success!");
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
app.js (node server):
/*========== Default Setup for node server copied from node website ==========*/
const http = require('http');
const hostname = '127.0.0.1';
const port = 3001;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello World\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
/*========== Listen for POST (Trying to get the data from my REACT app
- will then assign it to "obj" below) ==========*/
var express = require("express");
var myParser = require("body-parser");
var app = express();
app.post("./postJson/", function(request, response) {
console.log("MURRRR");
console.log(request.body); //This prints the JSON document received (if it is a JSON document)
/*=== JSON Stuff ===*/
var jsonfile = require('jsonfile')
var file = './scene-setup.json'
var obj = {name: 'JP'}
jsonfile.writeFile(file, obj, function (err) {
console.error(err)
})
});
//Start the server and make it listen for connections on port 3000
app.listen(3000, function(){
console.log("server is listening to 3000");
});
Two things I noticed:
Your post endpoint doesn't need a leading "." I would make it just "/postJson"
Make sure you are posting to "http://localhost:3000/postJson"
Make sure you have the network tab open to see the actual URL you are requesting to.
Cheers
Turns out both react and my node server were running on localhost:3000 simultaneously which is apparently not okay.
Running my node server on localhost:3001 from a new command line window allowed me to do both at the same time.
Not sure how this would work when making a production build though.

How to proxy a media stream in Node?

I want to be able to proxy a remote icecast stream to client. I've been fiddling around a lot in the past few days to no avail.
Use case:
Be able to extract analyser data out of an <audio> tag src without running into CORS issues.
My solution so far
In order to address CORS issues preventing me to create an leverage sound data directly out of the <audio>'s source, I've tried to write a tiny proxy which would pipe requests to a specific stream and return statics in any other case.
Here is my code:
require('dotenv').config();
const http = require('http');
const express = require('express');
const app = express();
const PORT = process.env.PORT || 4000;
let target = 'http://direct.fipradio.fr/live/fip-midfi.mp3';
// figure out 'real' target if the server returns a 302 (redirect)
http.get(target, resp => {
if(resp.statusCode == 302) {
target = resp.headers.location;
}
});
app.use(express.static('dist'));
app.get('/api', (req, res) => {
http.get(target, audioFile => {
res.set(audioFile.headers);
audioFile.addListener('data', (chunk) => {
res.write(chunk);
});
audioFile.addListener('end', () => {
res.end();
});
}).on('error', err => {
console.error(err);
});
});
app.listen(PORT);
The problem
The client receives a response from the proxy but this gets stalled to 60kb of data about and subsequent chunks are not received, in spite of being received by the proxy:
Any suggestion is welcome!
I've found a solution, use stream pipe.
const app = express();
const PORT = process.env.PORT || 4000;
let target = 'http://direct.fipradio.fr/live/fip-midfi.mp3';
// figure out 'real' target if the server returns a 302 (redirect)
http.get(target, resp => {
if(resp.statusCode == 302) {
target = resp.headers.location;
}
});
app.use(express.static('dist'));
app.get('/api', (req, res) => {
req.pipe(request.get(target)).pipe(res);
});
app.listen(PORT);

NodeJS HTTP proxy - Add a header and update the request URL

I am using this module to do the following:
Parse the req URL
Add a new header to the request using the token from the URL
Update the actual request URL (remove the token from the URL)
I am trying to do that with the following code:
function initializeServer(){
var server = app.listen(5050, function () {
var host = server.address().address
var port = server.address().port
logger.info('NodeJS Server listening at http://%s:%s', host, port)
});
}
proxy.on('proxyReq', function(proxyReq, req, res, options) {
console.log("intercepting ... ")
proxyReq.setHeader('x-replica', '123');
req.url = '/newurl';
});
function initializeController(){
app.get('/myapp*', function (req, res) {
proxy.web(req, res, { target: 'http://127.0.0.1:8081' });
});
}
where 8081 is my test server and proxy server runs at 5050.
Now, the header setting works but the setting the URL does not. How to achieve this with node HTTP proxy ?
In the proxy.on('proxyReq',...) handler req is the (original) incoming request, while proxyReq is the request that will be issued to the target server. You need to set the proxyReq.path field.

Resources