How to do serverside HTML5 mode URL Rewriting with NodeJS and browserSync - angularjs

How to remove #! getting added to url in my AngularJS application?
I have tried:- $locationProvider.html5Mode(true).hashPrefix('!'); and adding <base href="/"> but to no avail. When I navigate to a particular url, #! disappears but when I tried to reload, it gives the error:- Cannot GET.
So I looked online, and found out that doing above is only half of the solution. We also need to rewrite the logic on server side as well. So I am using NodeJS and browserSync package to fire up localhost. So what is the solutioin to this?
Note:- My backend and frontend code are separate and both handle routing.

There is a option in Browsersync called single which serves the index.html as a fallback if the url does not exist.
Serve an index.html file for all non-asset routes. Useful when using client-routers
See documentation:
https://www.browsersync.io/docs/options#option-single
browserSync.init({
server: {
baseDir: 'dist',
},
single: true
});

Related

How can i make my AngularJS website crawled on google?

I want to remove # from my angularjs app, I am developing an website, I think it may help to make SEO friendly website, May be i am wrong, Please help
Thanks
I agree with Joe Lloyd for the way to remove the # from your url but it won't help you to make your angularjs website crawlable.
Check out the following steps :
Configure the html5mode
config(function ($routeProvider, $locationProvider) {
$locationProvider.html5Mode(true);
Add <meta name="fragment" content="!"> to your pages so the google bot knows to add the ?_escaped_fragment_= at the end of your request.
Handle the ?_escaped_fragment_=on the server side and serve a static snapshot of the requested html page (phantomjs can make the job) so the bot will index the rendered version of the html page.
Populate your sitemap.xml and send it to google using www.google.com/webmasters/
Have fun !
Config
To remove the # in your url you need to add this to your main module. You put the app into html5 mode.
//This config is used to remove the # in the html
app.config(["$locationProvider", function($locationProvider) {
$locationProvider.html5Mode({
enabled: true,
requireBase: false
});
}]);
Server Side (NodeJS)
This will have a server side effect when you hit refresh you need to add an extra route that is able to find the new url. this will work in your express js app.js file. Where the public folder contains your angular app and you have your index.html file in there
// ### CATCH REFRESH TO INDEX ###
app.all('/*', function(req, res, next) {
// Just send the index.html for other files to support HTML5Mode
res.sendFile('public/index.html', { root: __dirname });
});

Issue after remove (#) hashbangs from routing in angular-ui-router

I have remove (#) hashbangs by $locationProvider.html5Mode(true) in ui-route.
and set <base href="/public/">
when I have tried to localhost:59940/public/#/home url # is remove and url look localhost:59940/public/home and getting home view.
but when I have tried localhost:59940/public/home url. I have getting 404 Not Found error.
help me for getting home view when try to access localhost:59940/public/home in browser.
The problem is that the browser resolves urls before your angular app responds, and indeed the resource for that route is not there. The solution I have used is to make your 404 route return the index.html page and use ui-router to handle real 404 cases. But another idea is to match all of the client routes to routes on your server which return the index.html.
To enable $locationProvider.html5Mode in angular, you also need to some side server changes.
Other then your static assets and apis path, all other routes should server index.html(your main SPA page) only.
See below code.
This is how you can do it in node.js using express server.
var app = require('express')();
app.configure(function() {
// Static files - all js, css, images, etc go into the static path
app.use('/static', express.static('/static'));
// If a static file is invalid so we send 404
app.use('/static', function(req, res, next) {
res.send(404);
});
// This route deals enables HTML5Mode by forwarding missing files to the index.html
app.all('/*', function(req, res) {
res.sendfile('index.html');
});
});
app.listen(3000);

Configure Amazon S3 static site with Angular JS ui.router html5Mode(true) on page refresh

How can I configure an Amazon S3 static webpage to properly route Angular ui.router html5Mode routes? On page refresh, it will make a request for a file that doesn't exist, and angular can't handle it. In the docs, they recommend changing your URL rewrites on the server.
https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-configure-your-server-to-work-with-html5mode
However, S3 is storage, and doesn't offer the same redirection options
I have been trying to use the built in redirection rules such as
<RoutingRules>
<RoutingRule>
<Condition>
<HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals >
</Condition>
<Redirect>
<HostName>[[ your application's domain name ]]</HostName>
<ReplaceKeyPrefixWith>#/</ReplaceKeyPrefixWith>
</Redirect>
</RoutingRule>
</RoutingRules>
However, this just leads to a redirect loop.
Any suggestions?
In the Frequently Asked Questions, they rewrite almost everything to serve the index.html page. For HTML5 fallback mode you need to use #!/ (hashbang).
You could change this:
<ReplaceKeyPrefixWith>#/</ReplaceKeyPrefixWith>
with
<ReplaceKeyPrefixWith>#!/</ReplaceKeyPrefixWith>
More details on this answer: https://stackoverflow.com/a/16877231/1733117
You may also need to configure your app for using that prefix:
angular.module(...)
...
.config(function($locationProvider) {
$locationProvider.html5Mode(true).hashPrefix('!');
})
Make sure you have the index route configured for your website. Mostly it is index.html
Remove routing rules from S3 configurations
Put a Cloudfront in front of your S3 bucket.
Configure error page rules for your Cloudfront instance.
In the error rules specify:
Http error code: 404 (and 403 or other errors as per need)
Error Caching Minimum TTL (seconds) : 0
Customize response: Yes
Response Page Path : /index.html
HTTP Response Code: 200
Basically there are 3 options, use an EC2 instance to perform the actual server rewrites to the configured HTML5 routes, or, like dnozay suggested, use the fallback mode and re-write requests to use the #! hashbang. Finally, you could just use the standard angular routes, which is the option I went with. Less hassle, and when Angular 2.0 rolls around, you can update to that.
https://stackoverflow.com/a/16877231/1733117
Doesn't really address the routing issue here.
here is another option using nginx proxy_pass, it also allows you to have multiple projects in subfolders and use subdomains
S3 Static Website Hosting Route All Paths to Index.html

AngularJS and Express Routing issue

I'm using AngularJS and ExpressJS and having an issue with routing. I saw many other posts but none of those solutions seemed to work. Here is my routes in Express:
module.exports = function(app, auth) {
//Api routes
var mycontroller = require('../app/controllers/mycontroller');
app.get('/api/dostuff/:id', mycontroller.getBlockByHash);
//Home route
app.get("/", function(req, res) {
res.render('index');
});
};
When I go to my root /, everything works as expected. ExpressJS serves up my index and angular picks up the rest. When I click a link /blocks, it works as expected since AngularJS picks up the route. But when I refresh, I get a 404 not found error.
I tried app.get('*' instead, but that gives me a completely different error where nothing loads.
I'm using Jade to create the basic page structure with Express. My Express config is:
app.use(express.favicon());
app.use(express.static(config.root + '/public'));
When using html5Mode the documentation says:
Using this mode requires URL rewriting on server side, basically you have to rewrite all your links to entry point of your application (e.g. index.html)
What it doesn't mention is:
You should exclude static assets like scripts/styles/images/fonts etc.
You should also exclude your Restful API.
Your case:
The error you got there is express serving html into script tags and the browser fails to parse them as a valid javascript.
Use express.static to serve static assets and then use app.get('*', for redirecting all other requests to your angular.js entry point (index.html).
express.js middleware order do counts!
express.static must be declared before app.router
Node.js / Express.js - How does app.router work?

AngularJS and PhoneGap: $location.path causes subsequent tempateUrl lookup to fail

I'm having trouble getting path lookup to work with a AngularJS v1.2.0 and PhoneGap/Cordova Android application. I've come pretty far with html5mode(true) by setting <base href="."/> in index.html and then changing $routeProvider.when('/') to $routeProvider.when('/android_asset/www/index.html'). After that I am able to get redirectTo('login') to reach $routeProvider.when('/login') and there render templateUrl: 'static/partials/login.html' as expected.
The problem I have is that if I instead try to redirect to the login page from my Javascript code with $location.path('/login');, the route is found but templateUrl loading fails with an insecurl exception.
I've tried whitelisting access to file:// by using the new angular-sanitize module, but that does not help.
How can I make $location.path() do the same things as redirectTo so that the partial is loaded? Or is there some other way to solve this problem?
UPDATE: I got a bit forward by adding a call to replace() after the path function, e.g.:
$location.path('/login').replace();
but that seems like a hack, and it still causes the templateUrl in the otherwise route to fail with the same exception.
Any ideas on what might be wrong? Is it that html5mode(true) just does not work at this moment with Phonegap and the only way to fix this is to set it to false and add hashtags to every path (like is done in the angular phonegap seed project)?
For future reference, this is how I managed to solve the problem:
AngularJS currently does not seem to support html5mode(true) inside a Cordova application because of the insecurl problem I reported. What I had to do is add
var h5m = (typeof html5Mode !== 'undefined') ? html5Mode : true;
$locationProvider.html5Mode(h5m);
which gives me the possibility to explicitly set html5Mode in the PhoneGap index.html with a global variable:
<script>
var html5Mode = false;
</script>
So now $location.path('/login') as well as redirectTo: 'login' works, but links in html files, don't. To get those working in PhoneGap, with html5Mode disabled, I had to add #/ in front of every link, e.g. login.
That makes PhoneGap work, but breaks the web page which uses History API with html5Mode(true). The last piece of the puzzle was to add <base href="/"/> to the web page's index.html (and leave it out of the index.html of the PhoneGap project.) So now even though I have a link that says #/login in the web page, I get to the url http://example.com/login and don't see any hashes in the address bar.
**
So in the end I have History API working in my web page and History API disabled in the PhoneGap project (where there really is no need for History API as there is no address bar). The only downside is the extra #/ I have to put in each template html file, but that is a minor annoyance compared to the ability to use all of the same html and javascript files for both web and mobile.
I had this same problem as well. I managed to fix it by skipping the leading slash in the route config:
$routeProvider
// route for the foo page
.when('/foo', {
templateUrl: 'foo.html', //previously: '/foo.html'
controller: 'fooController'
}) //etc.

Resources