Serving Temporary Pages with NodeJs - javascript

I'd like to start by letting everyone know that I am new to coding in node. With that out of the way let me explain what I am trying to build, I'm trying to build a site where a user can use a button on the main page to visit a page that has a randomized route, but only once. So once you have visited that route, you need to click on the link again to see the same contents but on a different route. That will ensure users have to click on the button and can't just cheat the system by entering the same link over and over. So in basic terms I need the app to:
-Temporarily serve a HTML form (to get information) on a randomized route/link (could be for a single request or for some time, say 10 minutes)
-Delete that route/link
-Start over
Here is the code I have so far:
const express = require('express')
const app = new express();
const fs = require('fs');
var link = Math.floor(Math.random() * (1000 - 0) + 0)
var changingroute = function (req, res, next) {
app.get('/' + link, function(req, res){
res.sendFile(__dirname + '/public/download.html');
});
setTimeout(endroute, 1000)
function endroute() {
app.delete('/' + link)
console.log('Route Closed: LocalHost:8080/', link);
}
link = Math.floor(Math.random() * (1000 - 0) + 0)
console.log('Route Opened: localhost:8080/',link);
next()
}
//app.use(changingroute);
const port = process.env.PORT || 8080;
app.use(express.static(__dirname + '/public'));
app.get('/', function(req, res) {
res.renderFile(__dirname + '/public/index.html');
});
app.get('/' + link, function(req, res){
res.sendFile(__dirname + '/public/download.html', '/public/download.html', function(err, res) {
if (!err) {
res.setHeader('Location', pathname + '/');
}
});
});
app.listen(port, function() {
console.log('app running');
console.log(`Route Opened: http://localhost:8080/${link}`);
});
Explanation:
The current code doesn't do what I would like it to. As you can probably tell changingroute isn't used, the app.use is commented. What it did do was create new routes every time a request was made but it wouldn't close the route afterwards. Where I was last with this code was testing out something someone else did on SO but it kind of differed from what I am trying to do : Serving Temporary Files with NodeJs. With their code you can put up files to download but only once but that doesn't really translate to routes and pages as I understand. I get errors like "cannot replace header" if I try and change the page it displays, or if I try and close the route. I haven't seen any tutorials online that show how to make temporary routes, or maybe I haven't used the right keywords. If you have any advice on where I should look or what I should try please let me know. I would really appreciate it!

Related

Document is not defined on node.js - How can i import a variable from another .js file to node.js server?

Edit: Actually, my problem is "How to use "value" from selection.js in the server.js ? " I want to direct user to a searching page according to his/her choice .
i am new at web programming. I have server.js and a selection.js.
server.js is a node file, and my server is in it. selection.js is my item class changer. I am changing selected item's class with selection.js and i am trying to use this selected item from server.js. When i try below codes, i am taking this shit: Document is not defined on node.js
It is really painful. I am trying to solve it about hours. But, nothing!
Pls, help me :/
selection.js :
var iconContainer = document.getElementById('iconContainer');
var icon = iconContainer.getElementsByClassName("item");
for (var i = 0; i < icon.length; i++) {
icon[i].addEventListener("click", function() {
var current = document.getElementsByClassName("active");
current[0].className = current[0].className.replace(" active", "");
this.className += " active";
const btnSearch = document.querySelector("#btnSearch");
btnSearch.addEventListener("click", () => {
// get the active item's value
const value = document.querySelector(".item.active span").innerText;
console.log("value: ", value);
// do fetch
});
});
}
module.exports={searchPath: "/"+value};
server.js:
var fs = require('fs');
var express = require('express');
var app = express();
var path = require('path');
app.use('/public', express.static(path.join(__dirname, 'public')));
// '/' girdisi için index.html getirilecek.
app.get('/', function (req, res) {
fs.readFile('index.html', function(err, data) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(data);
res.end();
});
});
//---------------------------------------------------
// Server kuruyoruz.
var server = app.listen(8081,"127.0.0.1", function () {
var host = server.address().address;
var port = server.address().port;
console.log('Server http://' + host + ':' + port+' adresinde çalışıyor...');
});
var search = require('./public/js/selection');
console.log(search.searchPath);
So, the code you label as selection.js needs to be in your web page, either directly embedded or linked from a <script> tag so it can run in the web page in the browser.
Then, that code can make an Ajax call using the XMLHttpRequest or fetch() interfaces in the browser to a route on your server and pass the desired value.
That route on your server (which you need to define and add code for) can then examine that value and decide what data to return the the Ajax call.
Your Javascript in the web page, then receives that returned data from the Ajax call and decides what to do with it such as insert new content in the page for the user to see, cause the browser to load a different page or refresh the current page or whatever else is appropriate.

Node.js, ajax - Frontend routing

I'm working on a SPA website with node.js, jQuery, mongoose and MongoDB for a shopping website.
The ajax requests and responses work perfectly when starting from the index.html file. So for example begining on http://localhost:3000 and someone clicks on a link called 'products' I send an ajax request to the the server and the server sends the necessary product information back asynchronously which lead to http://localhost:3000/products. But the problem is that if someone types http://localhost:3000/products directly in the search bar it will show the json representation of the products.
This is my code:
script.js
function redirect (link) {
$.ajax({
type: 'GET',
url: 'http://localhost:3000/' + link,
contentType: 'application/json',
data: {
link
},
success: function (res) {
let container = $('#contentToSwap');
container.html('');
res.products.forEach(function (products_) {
...
});
}
});
}
app.js
var Product = require('./models/product');
var mongoose = require('mongoose');
var bodyParser = require('body-parser');
var path = require('path');
var express = require('express');
var app = express();
mongoose.connect('mongodb://localhost:27017/shopping');
var PORT = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, 'public')));
app.use(bodyParser.json());
app.get('*', function(req, res) {
Product.find(function(err, docs) {
let productChunks = [];
let chunksize = 4;
let display = [];
for (var i = 0; i < docs.length; i++) {
if (docs[i].productType == req.query.link) display.push(docs[i]);
}
for (var i = 0; i < display.length; i += chunksize) {
productChunks.push(display.slice(i, i + chunksize));
}
res.send({ products: productChunks });
});
});
app.listen(PORT, function () {
console.log('Listening on port ' + PORT);
});
So I need some sort of frontend routing if the user doesn't start at the index.html file. I know that I could write my own router to route the urls correctly and that I could route all requests back to the index.html like
app.get('*', function(req, res) {
res.sendFile(__dirname + '/public/index.html');
});
But then I cannot load all the necessary product information from the server when someone clicks a link. So I'm a little bit confused on hwo to tackle this issue. Any help is appreciated
This is usually achieved by separating api routes from normal ones by adding specific url prefixes such as /api for all routes that return json data. What you can do is to specify /api/whatever-you-want, make it the target for your ajax call and place it above app.get('*' ....
Since routes and middleware functions are resolved top to bottom, it will be matched by your ajax call only, leaving the /products unaffected.
answer to question -- Is it possible to redirect user from /api/products to /product if the request wasn't generated by ajax?
Yes, it is possible by adding request query parameter to ajax call which will not be present on normal call and then check those on the server side and decided what to do if it (that specific query parameter) is missing or not.
Let's assume some client side JS that generates ajax call.
fetch('/api/products?api=true')
.then((data) => data.json())
.then((json) => console.log(json));
Notice the request url - /api/products?api=true
Now assume a normal call from html file.
products
These two calls differ in that api query parameter (ajax call has it, the other one doesn't).
And for the server side part of the task -- request query parameters object can be accessed via query property on request object (req.query).
app.get('/api/products', (req, res) => {
if (!req.query.api) {
// if get request doesn't contain api param. then
// handle it accordingly, e.g. do redirect
return res.redirect('/products');
}
// request comming from ajax call, send JSON data back
res.json({ randomStuff: 'abcd' });
});

Prime the website using Express JS

I really hope to find some answers here as i tried everything by now.
Background:
Overtime we deploy code to web server, we need to do a cache warm up, i.e. access the site and make sure it loads. First load is always the slowest since IIS require to do some manipulations with a new code and cache it.
Task:
Create a page which will a checkbox and a button. Once button is pressed, array of links sent to server. Server visits each link and provides a feedback on time it took to load each page to the user.
Solution:
I am using node JS & express JS on server side. So far i manage to POST array to the server with links, but since i have limited experience with node JS, i can not figure out server side code to work.
Here is a code i got so far (it is bits and pieces, but it gives an idea of my progress). Any help will be greatly appreciated!!!
var express = require("express");
var app = express();
var bodyParser = require('body-parser');
var parseUrlencoded = bodyParser.urlencoded({ extended: false});
var http = require("http");
function siteToPrime(url){
http.get(url, function (http_res) {
// initialize the container for our data
var data = "";
// this event fires many times, each time collecting another piece of the response
http_res.on("data", function (chunk) {
// append this chunk to our growing `data` var
data += chunk;
});
// this event fires *one* time, after all the `data` events/chunks have been gathered
http_res.on("end", function () {
// you can use res.send instead of console.log to output via express
console.log(data);
});
});
};
//Tells express where to look for static content
app.use(express.static('public'));
app.post('/', parseUrlencoded, function(request, response){
var newBlock = request.body;
console.log(Object.keys(newBlock).length);
var key = Object.keys(newBlock)[0];
console.log(newBlock[key]);
siteToPrime("www.google.com");
response.status(201);
});
app.listen(3000, function(){
console.log("Server listening on port 3000...");
});
Assuming that you have access to the array in the post route:
var express = require("express"),
request = require("request"),
app = express();
var start = new Date();
app.use(express.static('public'));
app.use(bodyParser.urlencoded({extended: false}));
function siteToPrime(req, res, urls) {
urls.forEach(function(url)) {
request(url, function(error, res, body) {
if (!error && res.statusCode == 200) {
console.log(url +' : ' + body);
console.log('Request took: ', new Date() - start, 'ms');
}
});
}
res.redirect('/');
};
app.post('/', function(req, res){
var urls = req.body.urls // Array os urls.
siteToPrime(req, res, urls);
});
app.listen(3000, function(){
console.log("Server listening on port 3000...");
});

Define pattern route for node js

I am using Node.js and express to make a web chat application. I have a question about routing.
My route is:
app.get("/", function( req, res ) {
res.sendfile( __dirname + "/index.html" );
});
And as far as I know it means all clients should go to http://www.example.com/index.html page to access the chat. ( maybe, not sure )
Is it possible to have a pattern URL like this:
app.get("/*", function( req, res ) {
res.sendfile( __dirname + "/*" );
});
so that any user can access to chat on any URL
In short: Something like facebook chat. which is accessible in all pages.
thanks in advance
Is it possible to have a pattern URL like this:
Yeah, Express supports exactly the route you listed. The documentation refers to it as an "unnamed wild-card."
// GET /foo -> (200) "foo"
// GET /baz/qux -> (200) "baz/qux"
app.get('/*', function (req, res) {
res.send(req.params[0]);
});
Though, for your example, Express/Connect includes a static() middleware for serving files by combining the URL path to a base directory:
app.use(express.static(__dirname));
Something like facebook chat. which is accessible in all pages.
This wouldn't necessarily have much of a relation to routing. Your application may need a route to gather a list of contacts or other persisted data, but the actual "chat" will be managed separately.
In general, it would depend on including common content in each page -- perhaps via a "layout" or "inheritance" if you're using views/templates -- to display the form for inputting message and an area to display chat history. Also, a fair amount of the "work" for the chat will have to be done client-side.
A quick example would be to serve the same file for multiple URLs:
var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io').listen(server);
app.get('/*', function (req, res) {
res.sendfile(__dirname + '/chat.html');
});
var chat = io
.of('/chat') // namespace
.on('connection', function (socket) {
socket.on('message', function (data) {
chat.emit('message', data);
});
});
server.listen(3000);
And, in that file:
<div id="chat-log"></div>
<form id="chat-send">
<input name="message">
<input type="submit" value="Send">
</form>
<script src="/socket.io/socket.io.js"></script>
<script>
var chatForm = document.getElementById('chat-send');
var chatLog = document.getElementById('chat-log');
var chatSocket = io.connect('/chat');
chatSocket.on('message', function (data) {
chatLog
.appendChild(document.createElement('div'))
.appendChild(document.createTextNode(data.text));
});
chatForm.onsubmit = function () {
chatSocket.emit('message', {
text: chatForm.message.value
});
chatForm.message.value = '';
chatForm.message.focus();
return false;
};
</script>
Then, from any address (GET /, GET /foo, GET /bar/baz/qux), you can access chat.
You're probably going to want to use a url param like this:
app.get("/:chatter",function(req,res){
console.log("the chatter is",req.param('chatter'));
res.sendfile( __dirname + "/index.html" );
...
});

Setup file-system based routing in Node

I'm really a fan of the simplicity PHP offers in serving pages, everything is based on the filesystem. I want to do the same thing with Node. I tried one routing setup that worked like this for views, but broke my public folder:
//using express:
app.get('*', function(req, res) {
file = req.params[0].substr(1, req.params[0].length);
console.log('requesting: ' + file);
res.render(file, {locals: {
req: req,
params: req.query
}});
});
So...What's the best way to setup filesystem based/php style routing in Node?
I think that I build exactly what you are looking for. I use this to serve up .jade files, obviously you can tweak this for your use case.
var url = require('url');
var express = require('express');
var app = express.createServer();
var fs = require('fs');
app.set("view engine", "jade");
app.use(app.router);
app.use(express.static(__dirname + '/public'));
/**
* Generic "get" attempts to route to known JADE files.
* If no known JADE files, then we pass routing to next() (should be static).
*/
app.get('*', function(req, res, next) {
var pathname = url.parse(req.url).pathname.toLowerCase(); // make matching case insenstive
// First case: with no path name, render the default index.jade
if(!pathname) {
res.render('index', {});
}
// Second case: path ending in '/' points to a folder, use index.jade from that folder
else if (pathname === '/' || pathname.charAt(pathname.length-1) === '/' ){
res.render(__dirname + '/views' + pathname + 'index.jade', {});
}
// Third case: looks like an actual file, attempt to render
else {
// Attempt to find the referenced jade file and render that. Note 'views' is default path.
fs.stat( (__dirname + "/views" + pathname + '.jade'), function(err, stats){
// There was an error, the file does not exist pass control to the static handler
if(err || !stats) {
next();
}
// We found the file, render it.
else{
res.render(pathname.substring(1), {});
}
});
}
});
app.listen(port);
Note, there should be more app.use() statements there for handling cookies, parsing the body etc. Also, the second param of the render is always empty. You may want to fill this out with things like {layout: xyz} or generic variables that need to come in to the rendered pages.
You can use express.static()
For examples:
app.configure(function(){
app.use(express.static(__dirname + '/public'));
});
app.configure(function(){
app.use('/uploads', express.static(PATH_TO_UPLOAD_FOLDER));
});

Categories