I have a sails app and the routes,static assets associated with the app are served from root and it works fine. I would like to add a express middleware so i could serve the routes and static assets in a specific path.
In order to serve the static assets i used the below inside the customMiddleware function in config/http.js,
app.use('/my/new/path', express.static(path.join(__dirname, '../client', 'dist')));
With the above in place i was able to load the static files both from the root as well as from the /my/new/path.
Now when it comes to route i'm not sure how to handle the sails route to load via express middleware using app.use, for example the home route defaults to '/' in my config/routes-client.js, instead of altering the route there i would like to use something like below which we normally use for a typical node/express app,
app.use('/my/new/path', routes); --> where routes is my server routes
Is there a way to add a express middleware to serve sails route on a specific path?
I'm not sure why you'd want to have a prefix added automatically to your custom routes rather than just adding the prefix directly to the routes in the config/routes.js (or config-routes-client.js) file, but here goes:
// config/http.js
middleware: {
reroute: function (req, res, next) {
// Set the prefix you want for routes.
var prefix = '/foo/bar';
// Create a regex that looks for the prefix in the requested URL.
var regex = new RegExp('^' + prefix + '(/|$)');
// If the prefix is found, replace it with /
if (req.url.match(regex)) {
req.url = req.url.replace(regex, '/');
}
// Continue processing the request.
return next();
}
}
Make sure you add reroute to the middleware.order array in config/http.js. Incidentally, this will take care of static files as well.
This is how I do it...
Inside http.js
var express = require('express');
module.exports.http = {
customMiddleware: function (app) {
app.use('/docs', express.static(path.join(sails.config.appPath, '/docs')));
},
... rest of the http.js code...
}
Of course in this example im serving docs folder from root of my app on route /docs... You addapt to your logic...
Related
I am trying to use static files in my project, but when the user makes a get request to my "/" landing page. I want to send non-static things like a json. But for some reason it just automatically sends my index.html in my static file.
const express = require("express");
const app = express();
app.use(express.static("public"));
app.get("/", (req, res) => { //This sends the user to the index.html even tho i want to send 123
res.send("123");
});
app.listen("3000");
As your code is written, the express.static() middleware looks at the / request, finds an index.html file in the public directory and serves that as the response for the / request. This is a feature of express.static() that is causing a conflict for you with your custom route for "/".
You have at least four choices for a solution here:
You can specify an option for express.static() to disable the index.html feature so it will avoid the "/" route and pass control on to your subsequent route handlers.
You can move the express.static() middleware AFTER your app.get("/", ...) route so that your custom route gets first dibs at the request.
You can remove the index.html file from your public directory so express.static() won't find it. Using a template system for all your HTML files that locates all HTML template files in some other directory that express.static() can't see (such as a views directory) would cause this to happen too or just moving it to some private directory and using it from your code from the private directory would work too.
Give ALL your static resources a common path prefix so there is never a URL conflict between static resources and custom route handlers.
The first option (disable index.html feature in express.static()) would look like this:
const express = require("express");
const app = express();
// disable index.html feature
app.use(express.static("public"), {index: false});
app.get("/", (req, res) => {
res.send("123");
});
app.listen("3000");
The second option (change the order of route definitions/middleware) would look like this:
const express = require("express");
const app = express();
app.get("/", (req, res) => {
res.send("123");
});
// put this after custom route definitions so they take precendence
app.use(express.static("public"));
app.listen("3000");
The fourth option (give all static resources a common path prefix) would look like this:
const express = require("express");
const app = express();
app.use(express.static("/static", "public"));
app.get("/", (req, res) => {
res.send("123");
});
app.listen("3000");
With this fourth option, you'd then have to prefix all your static URLs with the static prefix (which you can make anything you want) and thus "/" would never be a match for express.static().
Is there any particular reason that you have an index.html file inside your public directory and are serving something else? The convention is serve static assets such as CSS, JS, images etc. from your public folder, and HTML / templates in folder which would be a sibling of public such as views.
The browser will always default to rendering an index.html file if it is found in the root of the public directory. Move the HTML file to a separate folder and the route should work
app.use is a middleware, so whenever you're running a app, it always first go through the middleware, Try the below code
const express = require("express");
const app = express();
app.get("/", (req, res) => { //This sends the user to the index.html even tho i want to send 123
res.send("123");
});
app.use(express.static("public"));
app.listen("3000");
I have a folder called "Public" which contains an index.html file a long with some JavaScript and library files. When someone tries to access the products path (mydomain.com/products) I want to display that index.html file, but the client also needs to receive all the JavaScript and libraries. Here is the code for how I initially handle the HTTP request.
const express = require('express')
const app = express()
const bodyParse = require('body-parser')
const productRoutes = require('./api/routes/products')
const orderRoutes = require('./api/routes/orders')
app.use(bodyParse.urlencoded({extended: false}))
app.use(bodyParse.json())
// Routes which handle requests
app.use('/products', productRoutes)
app.use('/orders', orderRoutes)
In the products.js file, I continue the routing like this:
const express = require('express')
const router = express.Router()
router.get('/', (req, res, next) => {
/*res.status(200).json({
message: 'Handling GET requests to /products'
})*/
res.status(200).render("../../public")
})
The code I've commented out works perfectly fine, but I'm struggling to respond with the "public" folder page. I can't remember everything I've tried, but using .render or .sendFile on the "public" directory has not worked for me.
When I try to access the /products route, I'm hit with an empty error message. As it fails to return anything in the /products route, in continues down the file to an error handler. The error message is empty.
Any ideas on how to display the page with all the folder contents would be great!
Try: app.use('/products', express.static('public'))
This makes your "public" directory viewable from the /products route.
express.static() docs
You must config path for express static by :
//app.js | server.js
app.use(express.static(__dirname + '/public'));
Then, in example you have a file as : /public/you.html
In your app, you can use that file as path /you.html
And the same with all files type *.js, *.css,...
Fix error cannot view error
Run cmd npm install ejs
Att to app.js:
app.set('view engine', 'ejs');
After that, you create 1 file error.ejs at folder views :
//error.ejs
<%=error%>
Goodluck
I have made the express router with parameters
router.get ('/add') and it working fine. but when I added router.get ('/edit/:id'), express.static does not work, CSS and JavaScript external not working, what the problem with multiple parameters?
This my static settings
app.use(express.static(__dirname+'public'))
__dirname only returns path of your working directory not /end of your directory so you have to use / before your static file directory like.
app.use(express.static(__dirname + '/public'))
for multiple parameter with URL you have to write route according your need.
app.get('edit/:id/:value', (req, res) => {
/** for get these value from request use */
let id = req.params.id
let value = req.params.value
})
and your request URL should look like
http://localhost:port/edit/34/988978898
I'm using Node and Anugular, and I have created a RESTful api from my application, and created an angular resource to use this. I'm confused as to how the Angular ui-router directive reconciles with the Node Routing system on the server.
At the moment I have set up my routes/states in ui-router like this:
$stateProvier
.state('admin', {
url:'/admin',
templateUrl:'views/admin.html',
controller: 'adminController'
});
And this loads into the ui-view on my homepage, when I navigate to this url from a link on the loaded page.
HOWEVER, when I manually type in localhost/admin I get the route from Node, rather than the state render through angular.
Now I'd like to Angular to handle all the navigation on my app, and my resource to get the information, even if the address is typed manually into the navigation bar.
I've created a route in Node is for index, which contains my index.html page from angular, which effectively contains the whole app angular code, including all the routing.
My question is, how can I get angular redirect if I manually type the url into the address bar, and still have the data from the $resource.
I'm directing my resource to '/admin' - could this be the problem?
Does this mean that I need to add the contents of /routes/appointments' into the base node file (server.js), and then remove the route? If so then how do i direct my resource to the correct REST api?
app structure
public
-angular app
-app.js //for angular
routes
index.js
appointments.js
models
views
- index.ejs
server.js //node server file
here is my code exerpts
server.js
//standard routing code
var routes = require('./routes/index');
var appointments = require('./routes/appointments');
var app = express();
//configuring Express
app.set('port', process.env.PORT || 3000);
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.set('views', __dirname + '/views');
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use('/', routes);
app.use('/', appointments);
routes/index.js
var express = require('express');
var router = express.Router();
// ./routes/index.js
router.get('/', function(req, res) {
res.render('index', { title: 'Homepage' });
});
module.exports = router;
routes/appointments.js - this is the basis of my RESTFUL api
var express = require('express');
var router = express.Router();
var mongoose = require('mongoose');
var Todo = require('../models/Appointments.js');
/* GET /todos listing. */
router.get('/admin', function(req, res, next) {
Todo.find(function (err, todos) {
if (err) return next(err);
res.json(todos);
});
});
module.exports = router;
One way to do this is via the Accept header. If the request only accepts JSON then let the request go through to your API. If the request accepts HTML then always serve up your index page. Then once the index page loads angular's router will take care of the rest.
// Angular config - default Accept header for all ajax requests
$httpProvider.defaults.headers.common = {
'Accept': 'application/json'
};
// Middleware in Node to "intercept" non JSON requests
// Place this after express.static middleware but before your route definitions.
app.use(function(req, res, next) {
// keep in mind this applies to all requests, so 404s will need to be handled by your angular app since any url will serve up the index page
if(req.header('Accept') !== 'application/json') {
console.log('serving the index page');
req.url = '/'; // force the url to serve the index route.
}
next();
});
One more thing to note about this approach is that obviously you won't be able to see/debug your JSON data by hitting the URL directly anymore. There are several useful tools like Advanced REST Client or POSTman which actually give you better control and more options for things like that. Just make sure you set the Accept header in one of those tools and you'll be able to see the JSON response.
The actual URL is localhost#!/admin, try that. Angular hides the hashbang #!
Angular's URL routing is an "illusion" in that way. It only works on the client-side and only when your Angular app is loaded, which is on the main / route.
A solution could be to conditionally redirect from localhost/admin to localhost#!/admin, i.e. redirecting to your Angular app and passing it the #!/admin path. The condition could be a check for whether or not JSON was requested.
router.get('/admin', function(req, res, next) {
if(req.header('Accept') !== 'application/json')
return res.redirect('/#!/admin');
Todo.find(function (err, todos) {
if (err) return next(err);
res.json(todos);
});
});
You'll also need to configure Angular such that when it requests '/admin' json data from the server, it should only accept json (by setting the request header), which is how the the server will distinguish it from the regular '/admin' request. For that, if you're using $http.get you would do $http.get('/admin', {'Accept':'application/json'})
I am new to Express and semi-new to nodejs and I am trying to run a simple app / webserver as a proof of concept. I have been stuck for hours because my server serves every file as index.html (with the content of index.html).
In my index.html I am making calls to JS files and CSS files and they are all coming back but with a 200 in the console but they are all coming back with index.html content instead of the actual content contained in them. I believe the problem is in my server.js file which is below:
// server.js
// modules =================================================
var express = require('express');
var app = express();
var mongoose= require('mongoose');
var path = require('path');
// configuration ===========================================
// config files
var db = require('../config/db');
var port = process.env.PORT || 9999; // set our port
//mongoose.connect(db.url); // connect to our mongoDB database (uncomment after you enter in your own credentials in config/db.js)
app.configure(function() {
app.use(express.static(__dirname + '/public')); // set the static files location /public/img will be /img for users
app.use(express.logger('dev')); // log every request to the console
app.use(express.bodyParser()); // have the ability to pull information from html in POST
app.use(express.methodOverride()); // have the ability to simulate DELETE and PUT
});
// routes ==================================================
require('../../app/routes')(app); // configure our routes
// start app ===============================================
app.listen(port); // startup our app at http://localhost:9999
console.log('Magic happens on port ' + port); // shoutout to the user
exports = module.exports = app; // expose app
// app/routes.js
module.exports = function(app) {
// server routes ===========================================================
// handle things like api calls
// authentication routes
// sample api route
app.get('/api/nerds', function(req, res) {
// use mongoose to get all nerds in the database
Nerd.find(function(err, nerds) {
// if there is an error retrieving, send the error. nothing after res.send(err) will execute
if (err)
res.send(err);
res.json(nerds); // return all nerds in JSON format
});
});
// route to handle creating (app.post)
// route to handle delete (app.delete)
// frontend routes =========================================================
// route to handle all angular requests
app.get('*', function(req, res) {
res.sendfile('/Users/...../app/public/index.html'); // load our public/index.html file
//res.sendfile(path, {'root': '../'});
});
};
I have been following this tutorial verbatum: http://scotch.io/bar-talk/setting-up-a-mean-stack-single-page-application but haven't had much success.
I cannot confirm without looking at your computer but I get the feeling the paths in your application are wrong.
The crucial parts in the express setup are:
app.use(express.static(__dirname + '/public'));
and
app.get('*', function(req, res) {
res.sendfile('/Users/...../app/public/index.html');
The first rule catches and returns any static file in __dirname + '/public'.
The second returns index.html for anything else.
The problem is that your server.js is not in the apps directory (I can see this since you use ../../app/routes.js to get to routes.js) this means __dirname + '/public' is not pointing to the public directory. Which is why your static files are being served by the global rule in routes.js.
In order to fix this change __dirname + '/public' to ../../app/public, or better yet place your server.js file where it should be and update your paths.
I can also see you are using an absolute full path to index.html in routes.js instead of a relative one so it seems as if your applications needs to tidied out.
The tutorial that you are following contains this route
app.get('*', function(req, res) {
res.sendfile('./public/index.html'); // load our public/index.html file
});
which explicitly defines the behaviour you described.
In this tutorial it makes sense because it explains how to build a single page application. This type of the application typically returns the same content for all the request while the actual presentation work happens on the client by the client-side library (angular in this example).
So if you what to serve more pages with different content you need to add more routes for them, just like route for /api/nerds in the example.
Update:
After clarifying that the issue is incorrectly served CSS and JS files, the proposed solution is to check the location of the server.js - it should be in the folder together with the folder "public".