I'm running a NodeJS application and am visiting it at localhost/?product=test. I want to retreive 'test' (or any URL-related information for that matter).
Google shows me 2 options, but I can't get either to work:
Use HttpRequest
const http = require('http');
const url = require('url');
http.createServer(function (req, res) {
const queryObject = url.parse(req.url,true).query;
console.log(queryObject);
res.writeHead(200, {'Content-Type': 'text/html'});
res.end('Feel free to add query parameters to the end of the url');
}).listen(3000);
I'm trying to use this code, or variations on it, but the issue is that I cannot create a server to listen to because the address is already in use. I'm not too familiar with NodeJS, but what I don't understand is how to use a HttpRequest properly to listen to the running application and get its URL.
Use Express
Using express doesn't give an error, but all code snippets that -should- work return undefined for me when retrieving the URL.
What is a simple way to retrieve the URL the user used to visit my NodeJS app, so I can retrieve the parameters?
If you want to access localhost without filling in a port like here localhost/?product=test then you should listen to port 80 and not 3000. Otherwise your request should look like this: localhost:3000/?product=test
You should also create a route method for products. In express it will look like this:
const express = require('express')
const app = express()
const port = 80
app.get('/', (req, res) => res.send('home'))
app.get('/product/:productId', function (req, res) {
res.send(req.params)
})
app.listen(port, () => console.log(`Listening on port ${port}!`))
If you run this example your request url should be http://localhost/product/test and response will look like
{
"productId": "test"
}
Related
I am trying to pipe an image response from an internal API, using NodeJS Express to an external endpoint. I.e. proxying an image.
This is what I have tried, but I keep getting an empty box instead of the image:
app.get('/image', (req, res) => {
res.setHeader('Content-Type', 'image/png');
request.get(`http://localhost:8080/image`).pipe(res);
// Also tried reading from a file and not the endpoint
//to make sure it's not a problem with "request" library with same results
//fs.createReadStream('./image.png').pipe(res);
});
Using browser dev tools I can also see that the size of the empty image I get on the external endpoint is bigger then that of the working image got from the internal endpoint.
Accessing the endpoint from "Postman" seems to give the image without problems, but accessing from Firefox says that the image has errors.
So it seems to be some kind of an encoding issue which I can't seem to figure out how to fix. Please help.
Can't reproduce your issue. The below example works fine. Testing environment:
Microsoft Edge 86.0.622.38
E.g.
server-internal.ts:
import express from 'express';
import fs from 'fs';
import path from 'path';
const app = express();
const port = 8080;
app.get('/image', (req, res) => {
console.log('internal server /image');
res.setHeader('Content-Type', 'image/png');
fs.createReadStream(path.resolve(__dirname, './image.png')).pipe(res);
});
app.listen(port, () => console.log('HTTP server is listening on port:', port));
server-external.ts:
import express from 'express';
import request from 'request';
const app = express();
const port = 3000;
app.get('/image', (req, res) => {
console.log('external server /image');
res.setHeader('Content-Type', 'image/png');
request.get(`http://localhost:8080/image`).pipe(res);
});
app.listen(port, () => console.log('HTTP server is listening on port:', port));
Access http://localhost:3000/image, got the image correctly.
The logs of the internal server:
HTTP server is listening on port: 8080
internal server /image
The logs of the external server:
HTTP server is listening on port: 3000
external server /image
source code: https://github.com/mrdulin/expressjs-research/tree/master/src/stackoverflow/64302729
Thank you slideshowp2 for taking your time and pointing out that, my provided code should indeed work.
It would have been impossible to figure out the issue with the info that I gave.
I was using "livereload" middleware in my project.
This middleware intersects all the responses coming from my server and tries to inject the liverelad script into them.
By default it is configured to ignore responses for endpoints ending with ".png" and other image and binary formats.
Adding ".png" to the endpoint path, solved the issue.
app.get('/image.png', (req, res) => {
request.get(`http://localhost:8080/image`).pipe(res);
});
I have a frontend-only web application on Netlify which has to consume an API on OpenSubtitles.org. Although OpenSubtitles.org enables CORS, sometimes I got preflight errors, so I decided to use a proxy.
I had problems using Netlify's proxy feature, so I decided I will create my own proxy on Heroku, and send my requests from the frontend to there, so these will be proxied to OpenSubtitles.org from a server.
I came up with the following based on the code I found here:
const express = require('express');
const request = require('request');
express()
.use('/', function(req, res) {
req.pipe(
request({
url: 'http://rest.opensubtitles.org/search' + req.url,
headers: {
'User-Agent': 'TemporaryUserAgent'
}
})
).pipe(res);
})
.listen(process.env.PORT || 8000);
I thought I deploy this, try it out, then I will enable CORS on it after that. However I've just realized it is working perfectly without doing anything else. How is it possible? Why can I call this from a frontend-only app on a different domain without explicitly enabling CORS?
Also, what if the server crashes, how to handle the errors there?
CORS is working because the url you're requesting responds with the header Access-Control-Allow-Origin set with a value of *. Since you're piping that response and its headers back to the original res object, it will enable CORS as if it was coming from your local proxy.
Below is a more straightforward example of how to proxy a request to another site and return its response intact using node streams.
const express = require('express')
const request = require('request')
const port = process.env.PORT || 1337
let server = express()
const proxyMiddleware = (req, res, next) => {
let url = `https://www.google.com/${req.url}`
let proxyRequest = request(url)
// Pass request to proxied request url
req.pipe(proxyRequest)
// Respond to the original request with the response from proxyRequest
proxyRequest.pipe(res)
}
server.use(proxyMiddleware)
server.listen(port, () => console.log(`Listening on ${port}`))
I'm completely new to server development and NodeJS, so my apologies if this question sounds stupid or if such a question already exists.
I was following a simple NodeJS tutorial and building a simple "Hello World" server. I noticed that http.createServer took only one function as its argument.
http.createServer(function(req,res) {
res.writeHead(200, {'Content-Type' : 'text/html'});
res.end("Hello World");
}.listen(8080);
I tried passing another function to it like the following:
var http = require('http');
http.createServer(function(req,res) {
res.writeHead(200, {'Content-Type':'text/html'});
res.end("Hello World");
},
function (req, res) {
res.write("Blahblah");
res.end();
}
).listen(8080);
But hitting localhost:8080 returned only Hello World.
So I was wondering if I could pass multiple functions to it and if not, then why.
Thank you for your time
You cannot pass multiple functions. If you want multiple listeners for incoming requests, you can just register another listener for incoming requests:
const server = http.createServer(function(req,res) {
res.writeHead(200, {'Content-Type' : 'text/html'});
res.end("Hello World");
}.listen(8080);
// add additional listener
server.on('request', function(req, res) {
if (req.url === "/goodbye") {
res.writeHead(200, {'Content-Type' : 'text/plain'});
res.end("goodbye");
}
});
Note: right from the doc for http.createServer(), it says this about the function parameter passed to http.createServer():
http.createServer([options][, requestListener])
The requestListener is a function which is automatically added to the 'request' event.
Doc for the request event is here.
As others have said, it is pretty rare to use a plain http server like this because some simple routing is nearly always helpful and a lightweight framework like Express offers very useful features without really getting in the way of anything you might want to do. In the case of Express, you'd use code like this:
const express = require('express');
const app = express();
// define handler for /goodbye URL
app.get('/goodbye', function(req, res) {
res.send("goodbye");
});
// define handler for /hello URL
app.get("/hello", function(req, res) {
res.send("hello");
});
const server = app.listen(8080);
Here express, keeps a list of the URLs that you wish to handle and then listens for each incoming request, compares it against the URLs you wanted to handle and calls the appropriate route handler. It has lots of other features for routing too such as middleware, wildcards, parameterized URLs, etc...
I'd recommend you use something like express if you want multiple routes:
const express = require('express');
const app = express();
app.get('/hello', (req, res) => res.send('Hello World!'));
app.get('/world', (req, res) => res.send('Hello World!'));
app.listen(3000, () => console.log('Example app listening on port 3000!'));
Node.js provides you with the features to create your own webserver from scratch, unless you want to create a whole new framework i would recommend using something like expressjs.
Have a look at this following tutorial if you're a newbie and want to create restful services.
Build a RESTful API Using Node and Express 4 | Scotch.io
Its a fairly simple and straightforward tutorial
I try to run simplest Express code on Cloud server
var express = require('express');
var app = express();
app.get('/test', (req, res) => res.send('Hello '));
app.listen( 3000 );
I am getting the Apache 404 error : GET /cood180119/projExpress1/demo1/test HTTP/1.0, Cannot GET /cood180119/projExpress1/demo1/test
I have noticed that my url is http://77.xx.xx.xx/cood180119/projExpress1/demo1/test
while error logs shows IP : 88.xx.xx.xx.
How to resolve?
I have a node hello world example, which is working with the following url:
http://77.xx.xx.xx/node-hello-world-master/
where the file is in public_html/node-hello-world-master/app.js,
but does not work with http://77.xx.xx.xx:3000/
const http = require('http');
http.createServer(function(request, response) {
response.writeHead(200, {'Content-Type': 'text/plain'});
response.end("Hello, World!\n port= ' + process.env.PORT);
}).listen(process.env.PORT); //is says that port is undefined
I set the port=3000 in environmental node variables.
After this, i can get the port number echoed , but i still can not access webpage using ttp://77.xx.xx.xx:3000/
Seems firewall is configured wrong.
I think you are requesting the wrong URL.
app.get('/test', (req, res) => res.send('Hello '));
app.listen( 3000 );
this will always produce a route as follows
'http://ip:3000/test
why do you use cood180119/projExpress1/demo1 in your URL. I don't see any route defined for that.
Your route
app.get('/test', (req, res) => res.send('Hello '));
make sure that the URI (or the path in this case /test) of the request you want to capture exists.
My problem:
The name of html file was not exactly "index.html"
So, I renamed it and it worked perfectly!
app.use(express.static('public'));
Note: public is a folder inside my server directory witch contains index.html and styles.css.
In my scenario I need forward get request to another end point. In my machine there are two servers php and node.js server. Node.js is like a "man in the middle", PHP server must work in the same way.
Node.js server code
var express = require('express');
var fs = require('fs');
var path = require('path');
var http = require('http');
var https = require('https');
var app = express();
var HTTP_PORT = 3000;
// Create an HTTP service
http.createServer(app).listen(HTTP_PORT,function() {
console.log('Listening HTTP on port ' + HTTP_PORT);
});
//endpoint for tracking
app.get('/track', function(req, res) {
sendRequestToOtherEndPoint(req);
processRequest(req);
res.setHeader('Content-Type', 'application/json');
res.send('Req OK');
});
function processRequest(req){
console.log("request processed");
}
function sendRequestToOtherEndPoint(req){
//magic here :)
}
When this server receive a get request in port 3000, it process request information and it must forward the same requesto to another end point.
For example:
Get localhost:3000/track?param1=1¶m2=2
Server process get request
Server forward get request to localhost/final-endpoint?param1=1¶m2=2
Depending on what you're trying to do, you can create a new request to the end-point:
//endpoint for tracking
app.get('/track', function(req, res) {
req.get({url: 'http://end-point', headers: req.headers});
processRequest(req);
res.setHeader('Content-Type', 'application/json');
res.send('Req OK');
});
More info: https://github.com/request/request
There are a couple of useful libraries that one could use:
http-proxy-middleware:
const proxy = require('http-proxy-middleware')
var apiProxy = proxy('/track', {target: 'http://end-point'});
app.use(apiProxy)
axios-express-proxy
import express from 'express';
import { Proxy } from 'axios-express-proxy';
const app = express();
const port = 3000;
app.get('/track', (req, res) => Proxy('http://end-point', req, res));
In you case res.redirect might help.
app.get('/track', function(req, res) {
// process the request
// then redirect
res.redirect('/final-endpoint');
});
Then catch the redirected request in final endpont.
app.get('/final-endpoint', function(req, res) {
// proceess redirected request here.
});
See the Express docs
If your second endpoint is on a different server, (e.g. PHP) then you're going to need to either redirect the client (as in sohel's answer), or spoof a request from Node to the PHP server and then send the response back to the client. This latter option is definitely non-trivial so I would question whether it's crucial not to use a client redirect.
If you're talking about two express endpoints, then I think the simplest answer might be not to actually forward at all, but just use the endpoint callback directly instead:
app.get('/track', trackCallback);
app.get('/otherendpoint', otherendpointCallback);
function otherendpointCallback(req, res) {
// do your thing
}
function trackCallback(req, res) {
otherendpointCallback(req, res);
processRequest(req);
res.setHeader('Content-Type', 'application/json');
res.send('Req OK');
};
Depending on exactly what you want to do at the other end point, you might need to spoof some of req's fields (e.g. req.url)