A Node.js app needs to:
1.) receive data from another serve that calls /some_endpoint,
2.) process the data it receives to create a String result jwtString,
3.) redirect the user to the root / url of the AngularJS app while passing the jwtString as a res.header included inside the res.redirect.
What specific changes need to be made to the Node.js routing code below in order for the _jwt header to be successfully passed from the Node.js app to the client AngularJS at at /?
app.get('/some_endpoint', function(req, res) {
//Process data from another server that was redirected here.
//then send the result of that processing in jwtString while
//redirecting user to the root url of the Angular app that
//is served by this Node.js instance.
res.setHeader('_jwt', jwtString);
res.redirect('/');
});
app.get('*', function(req, res) {
var queryData = url.parse(req.url, true);
console.log('in get *, queryData is: ');console.log(queryData);
res.sendfile('./public/index.html'); // load the single view file (angular will handle the front-end)
});
When I run the code above, I cannot seem to find the _jwt header in the Network tab of the FireFox developer tools.
Related
I am creating a MERN app that adds meta tags to React pages without SSR. So, I need to read the query inside the main file of the server and pass the appropriate metadata content to each page.
I am using this in the server.js file:
const indexPath = path.resolve(__dirname, 'build', 'index.html');
// static resources should just be served as they are
app.use(express.static(
path.resolve(__dirname, 'build'),
{ maxAge: '30d' },
));
// here we serve the index.html page
app.get('/*', (req, res, next) => {
fs.readFile(indexPath, 'utf8', (err, htmlData) => {
if (err) {
console.error('Error during file reading', err);
return res.status(404).end()
}
// get post info
const postId = req.query.id;
const post = getPostById(postId);
if(!post) return res.status(404).send("Post not found");
// inject meta tags
htmlData = htmlData.replace(
"<title>React App</title>",
`<title>${post.title}</title>`
)
.replace('__META_OG_TITLE__', post.title)
.replace('__META_OG_DESCRIPTION__', post.description)
.replace('__META_DESCRIPTION__', post.description)
.replace('__META_OG_IMAGE__', post.thumbnail)
return res.send(htmlData);
});
});
Here the getPostById is statically defined in a file. But I want to fetch it from my db.
My file structure is:
server.js
controllers
- posts.js
routes
- posts.js
I've separated the logic from route. So my routes/posts.js file looks like:
import { getPost, createPost } from '../controllers/posts.js';
const router = express.Router();
router.get('/', getPost);
router.post('/', createPost);
export default router;
So, in order to dynamically pass the meta content, I need to read the API endpoint for each request and pass the appropriate data. For this, I need to call the endpoints directly inside my node project. How to do that?
I'd appreciate any help. Thank you.
If you really want to call your own http endpoints, you would use http.get() or some higher level http library (that is a little easier to use) such as got(). And, then you can make an http request to your own server and get the results back.
But ... usually, you do not make http requests to your own server. Instead, you encapsulate the functionality that gets you the data you want in a function and you use that function both in the route and in your own code that wants the same data as the route. This is a ton more efficient than packaging up an http request, sending that request to the TCP stack, having that request come back to your server, parsing that request, getting the data, forming it as an http response, sending that response back to the requester, parsing that response, then using the data.
Instead, if you have a common, shared function, you just call the function, get the result from it (probably via a promise) and you're done. You don't need all that intermediate packaging into the http request/response, parsing, loopback network, etc...
I need Express server to serve static files (website). It works in my code well:
var express = require('express');
var app = express();
var path = require('path');
var p = path.join(__dirname, '../web/public');
app.use("/files", function (req, res) {
return res.send("I will do something on server");
});
app.use(express.static(p));
app.use('/*',express.static(p));
let port = 80;
var server = app.listen(port);
But when I have a form served by this server, it redirects after submit, and the page displays only something like
Cannot POST /dashboard/
How can I correctly handle post requests within the meaning of serving static files? I tried to add this right before declaring the port:
app.post(express.static(p));
app.post('/*', express.static(p));
But it doesn't work.
PS: my entire page is served (I want that) from index.html. In order to do that, I have in my code that:
app.use(express.static(p));
app.use('/*',express.static(p));
How do I "redirect" post requests to index.html? In this file I have the entire app logic (it is a single page app).
PS2: I really need default submit. Going around that is not a solution for me (I want to offer the user to save their login and password, and without submitting the form, Google chrome will not offer that to users). And on the other side I really need use POST, as the login form is transferring sensitive data...
Any ideas?
Thanks!
There is no file called dashboard so there is nothing for express.static to serve.
To handle that dashboard route, you can do this:
app.post("/dashboard", function (req, res) {
return res.send("I will do something with this post");
});
If you want to redirect 404 traffic to index.html, you can do this after all your route definitions:
app.use("/", function (req, res) {
return res.redirect("/index.html");
});
I am currently using Express to load a one page client side app in React.js and react-router.
It is structured such that I have /about and /contact as standard jade views, but /ui as the actual react app. Any subsequent navigation beyond /ui such as ui/dashboard is handled by react-router. This means that if I need to visit www.foobar.com/ui/dashboard, I would need to hit my route for ui*, grab the url past ui/ (dashboard in this case) and pass that to react router (via variable in the jade view which is the react app's entry point) which then loads this route from a react component. I would like to make this approach work as this enables users to save urls for the react app. Trouble is I can't figure out how this could work as:
I cannot pass variables with express router redirects
I need to load the react app without anything beyond /ui as otherwise react router will append its routing urls in front of it ruining the point in this approach
I cannot store the initial request url in a cookie and then redirect as I need to send a response in order to set a cookie
I cannot satisfactorily modify the url via client side js
Code:
//Example 1
router.get('/ui*', requireLogin, function(req, res){
res.render('./app/index', {initURL: req.path); //Doesnt work as everything past ui/ is still present when react-router does its thing
});
//Example 2
router.get('/ui', requireLogin, function(req, res){
res.render('./app/index', {initURL: req.path); //Doesnt work as no way of accessing the initial requests url when redirecting
});
router.get('/ui*', requireLogin, function(req, res){
res.redirect('/ui'); //Cant pass additional parameters here
});
var express = require('express')
var React = require('react')
var Router = require('react-router')
var routes = require('./routes')
var app = express()
app.use('/ui', requireLogin, function(req, res, next) {
// store initially requested url as a query parameter
// e.g. /ui/dashboard would become /ui?redirect=dashboard
// if the user is not logged in
var params = req.query;
// params.redirect === 'dashboard'
// Now you can check if there is a redirect and use it in your initial route
var router = Router.create({location: req.url, routes: routes})
router.run(function(Handler, state) {
var html = React.renderToString(<Handler/>, {initalState: params.redirect})
return res.render('react_page', {html: html})
})
})
Does this get you on the right track?
I think you have to distinguish your client side routing and your server side routing.
You will need a server side routing:
the client needs to load the static content (*.html, *.js, *.css)
the client needs to authenticate, and load the data he needs (/api/...)
You will also need a client side routing framework (like ui.router for angular.js):
you will split your client application logically in different routes that the browser (user) can remember, like /, /dashboard, /...
Regards, Remy
I'm using the mean.js (http://meanjs.org/generator.html) boilerplate as a starting point for an app, as I love the inbuilt authentication/authorization.
However, I'm having a problem with using HTML5.
In my angular app i've set HTML5(true) and I know that I need to set up a catchall route for all the other requests to be redirected.
I have the following routes on my express as the root and catchall:
///this is the app/controllers/core.server.controller:
exports.index = function(req, res) {
res.render('index', {
user: req.user || null,
request: req
});
};
exports.catchall = function(req, res){
res.redirect('/');
};
And then the routing itself
'use strict';
module.exports = function(app) {
// Root routing
var core = require('../../app/controllers/core.server.controller');
app.route('/').get(core.index);
app.route('*').get(core.catchall);
};
now the pages are redirecting no problem when I enter routes that are just garbage, but when I enter a route that exists in express (with no associated view I'm getting server output).
Here is the route i mean for express:
'use strict';
/**
* Module dependencies.
*/
var users = require('../../app/controllers/users.server.controller'),
articles = require('../../app/controllers/articles.server.controller');
module.exports = function(app) {
// Article Routes
app.route('/articles')
.get(articles.list)
.post(users.requiresLogin, articles.create);
// Finish by binding the article middleware
app.param('articleId', articles.articleByID);
};
I have no view associated with this in Express/Node - just in Angular.
so when I navigate to localhost:3000/articles via a link the angular manages the route and renders the correct angular template.
However, when enter localhost:3000/articles and press enter (or refresh the browser on this url) I get the following:
[{"_id":"5555ede9dac9d0d99efae164","user":{"_id":"5554fa21141c5aef7b0354d7","displayName":"heny as"},"__v":0,"content":"This is the blurb for him","title":"VP, Global Marketing","created":"2015-05-15T13:00:25.177Z"}]
but I want to get getting the rendered page template from angular
Can anyone help?
This is because you call the server url (wich is the same used for ajax calls), you need to
Either intercept request type in the server side (ajax | not ajax) and redirect all no ajax to root path (/) and angular will use ajax to get articles in client side.
Define a single root (/) for serving your single web application and use (/api/...) to handle all your ajax requests.
I am building a webservice, for which i am using nodejs, phantomjs and expressjs. I am learning all the three.
I want to serve a delayed response to the clients after processing their query. Like for example,
I am processing certain inputs from my client, then, i want to process the data at the backend which will take approx 10 sec on an avg. Then i wanted to serve this page to the client.
Is it possible in node to send multiple responses to the same request or delayed responses so that the template will automatically update the contents.
Or , should i use the same method , like store the json in a file in the server , then serve the page with ajax which will query the page.
please help me. here is the code which i wrote ,
app-server.js(the main file):
// import express module
var express = require('express');
var bodyParser = require('body-parser');
var app = express();
// define all required template files to be served and also define the template engine
app.engine('.html', require('ejs').__express);
app.set('views', __dirname + '/views');
app.set('view engine', 'html');
// Useful modules
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
// import the routes
require('./router')(app);
app.listen(8080);
router.js:
var crypto = require('crypto');
var express = require('express');
module.exports = function (app) {
// define the static routes.
app.use('/static', express.static('./static'));
app.use('/media', express.static('./media'));
//defining the controller.
var parserlib = require('./controller.js')
// Define the home root path
app.get('/', function (req, res) {
// shows the home search page.
res.render('index', {content:'template success'});
});
app.get('/search', function(req, res){
res.redirect('/');
});
app.post('/search', parserlib.parserlib);
}
controller.js:
var crypto = require('crypto');
var path = require('path')
var childProcess = require('child_process')
exports.parserlib= function(req, res){
var output = '';
var url = req.body.search_url;
var childArgs = [
path.join(__dirname, 'external-script.js'),
url,
]
// execute the script in a separate thread.
childProcess.execFile(binPath, childArgs, function(err, stdout, stderr) {
// handle results
console.log(stdout);
output = stdout;
//console.log(err);
//res.send(output);
});
//res.send(output);
};
so , what i want to see is, first send a response to client stating that its loading, then i want to update the with processed data. In other languages its not possible to send multiple responses. Not sure about nodejs.
Also, do i have to store the json output from the processed lib to a file and then use ajax to query ? or is it possible to directly update the json object to the client ?
Thanks
This is just not how HTTP works. The clients won't expect it. This has nothing to do with Node or any other framework. The way to do what you're attempting is to actually send a response that the thing is loading, and then have some other mechanism for reporting state.
As an example, you might design a RESTful API. In that RESTful API you might define a endpoint for creating new things:
POST /api/things
The client would post data to that to create a new thing. The response should be something that provides a location of the newly created resource, for example an HTTP 301 to /api/things/1.
If the user goes to /api/things/1 and the thing isn't done getting made yet, then you can either do a temporary redirect (303) to /api/things/1/status which provides some helpful status information, or just issue a 404.
If you actually want to send back server-side pushes of status information, then you should be looking at WebSockets or a pure Socket API of some kind, neither of which is provided by Express, but both of which are available in Node (checkout the socket.io library and the net core library)