Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Refreshing page shows file not found error how to resolve using [angular js + NodeJS/ExpressJS ]

Tags:

Note: I tried all questions & answer related this topic. Like This and I tried related questions and try to solve it but not success.

I am building angularJS web-app. It's purely based on AngularJS/HTML5 and NodeJS/ExpressJS and Database side use mongo DB then this problem occurs.

I want To '#' remove in url and I refresh page then display my current page .But right now display "Not Found 404".I use like this $locationProvider.html5Mode(true); and <base href="/" /> but I am not success.

I know remove # in URL solution is $locationProvider.html5Mode(true);and <base href="/" /> But i use NodeJS/ExpressJS then I can't use.

My Url

http://localhost:3000/Tutorial/Routing/StateProvider/index.html#/Setting/StudenList

I want to URL

http://localhost:3000/Tutorial/Routing/StateProvider/index.html/Setting/StudenList

Notes:

Without this Solution $locationProvider.html5Mode(true);and <base href="/" /> But i use NodeJS/ExpressJS Then I want to remove # and refreshing page issue solve

Code

Folder Structure directive .my code very long then i mange snippet (inside html & js ). Not run snippet because i insert all my code just for understand what is mistake my code.

sample2(refreshissue) [Project Name]
-- Public
    -- Tutorial
        --Directive
            -index.html
        --Routing
           --StateProvider
                -Account.html
                -index.html
                -Setting.html
                -StudentListing.html
                -studentDetails.html
                -StateProviderController.js
        --Validation
          -index.html
 -index.html

--  StateProviderController.js
---------------------------------------------------------------------------------
var myapp= angular.module('myapp2',["ui.router"]);
myapp.config(function($stateProvider,$urlRouterProvider,$locationProvider,$urlMatcherFactoryProvider){
    $urlMatcherFactoryProvider.strictMode(false);
    $stateProvider
.state('TutorialHome', {
            url:'/index',
            templateUrl:'/index.html'
        })
        .state('Profile',{
            url:'/Profile',
            templateUrl:'Profile.html'
        })
        .state('Account',{
            url:'/Account',
            templateUrl:'Account.html'
        })
        .state('Setting',{
            url:'/Setting',
            templateUrl:'Setting.html'
        })
        .state('Setting.StudenListing', {
            url:'/StudenList',
            views: {
                'StudenListing': {
                    templateUrl: 'StudenListing.html',
                    controller:'StudentListingData'
                }
            }
        })
        .state('Setting.StudenListing.StudentList',{
            url:'/StudenList/:StudentID',
            /* templateUrl: 'StudentDetails.html',
            controller:'StudentDetails'*/
            views:{
               'StudentDetails': {
                   templateUrl: 'StudentDetails.html',
                   controller:'StudentDetails'
              }
            }
        })
    ;

   // $urlRouterProvider.otherwise('/index');
 //$locationProvider.html5Mode(true);

});
myapp.controller('StateProviderCtrl',function($scope){
    $scope.message ="Welcome To State Provider Page";
    $scope.Home = function()
    {
        window.open('/',"_self");
    }
});

myapp.controller('StudentListingData',function($scope,$http){
    console.log('test');
$http.get('/StudenRecordData').success(function(response){
   // console.log(response);
    $scope.StudentRecorddata =response;
})
});

myapp.controller('StudentDetails',function($scope,$http,$stateParams){
    $scope.StudentID = $stateParams.StudentID;
    //console.log( $scope.StudentID);

    $http.get('/StuentRecordSearch/'+ $stateParams.StudentID).success(function(response){
        //console.log(response);
        $scope.StuentDetails =response[0];
    })

});
==================================================================================================================================================================
----  app.js
---------------------------------------------------------------------------------
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var url =require('url');

var index = require('./routes/index');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');


//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', index);
/*var basepathArray = ['/Tutorial/Routing/StateProvider/','/Tutorial/Validation/','/Tutorial/Directive/'];
app.get('/!*',function(req,res){
  var basePath ="";
  for(var i=0;i<=basepathArray.length-1;i++)
  {
    if(req.originalUrl.search(basepathArray[i]) != -1){
      basePath =basepathArray[i];
      break;
    }
  }
  if(basePath!="")
  {
    res.sendFile(path.resolve('public'+basePath+'index.html'));
  }
  else {
    res.sendFile(path.resolve('public/index.html'));
  }



});*/

// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});



module.exports = app;
=================================================================================
 --  Account.html
---------------------------------------------------------------------------------
<h1>Account  page</h1>

=================================================================================
--  index.html
---------------------------------------------------------------------------------
<!DOCTYPE html>
<html ng-app="myapp2">
<title>Index | Angular Js</title>
<base href="/Tutorial/Routing/StateProvider/" />
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js"></script>
<!--<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-route.js"></script>-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/0.3.2/angular-ui-router.js"></script>
<script src="StateProviderController.js"></script>

<body ng-controller="StateProviderCtrl">
<nav class="navbar navbar-default row">
    <div class="container-fluid">
        <div class="navbar-header">
            <a class="navbar-brand" ui-sref="TutorialHome"> State Routing</a>
        </div>
            <ul class="nav navbar-nav">
                <li><a ui-sref="Profile">Profile</a></li><!--State Transition on click-->
                <li><a ui-sref="Account">Account</a></li><!--State Transition on click-->
                <li><a ui-sref="Setting">Setting</a></li><!--State Transition on click-->
                <li style="float: right;" ><a ng-click="Home()"> Home</a></li><!--State Transition on click-->
            </ul>

    </div>
</nav>


<div class="container" ng-controller="StateProviderCtrl">
    <!-- we use ui-view instead of ng-view -->
    <!--{{message}}<br>-->
    <ui-view></ui-view>

</div>


</body>
</html>
=================================================================================
--  Profile.html
--------------------------------------------------------------------------------
<h1>Profile  page</h1>

=================================================================================
--  Setting.html
---------------------------------------------------------------------------------
<div>
    <h1>Setting page</h1>
    <strong>This page shows Nested states & views. Click on below links to see Nested states in action.</strong><br>
    <ul>
        <li><a ui-sref="Setting.StudenListing">Show Listing</a></li>
    </ul>
    <div class="container">

        <div class="row">
            <div class="col-sm-12" style="background-color:beige;display: inline-block">
                <div ui-view="StudenListing"></div>
            </div>
        </div>
    </div>

</div>
  <!--  <div ui-view="Descriptions"></div><br>
    <div ui-view="Price"></div>-->
=================================================================================
--  StudentListing.html
---------------------------------------------------------------------------------
    <!--<ui-view></ui-view>-->


    <div class="row">
        <div class="col-sm-6" style="background-color:beige;">

            <h2>Student Listing</h2>
            <p>All Talented Student List</p>
            <table class="table" >
                <thead>
                <tr>
                    <th>Name</th>
                    <th>Eduction</th>
                    <th>Email ID</th>
                    <th>Details <!--<div ui-view="StudentDetails"></div>--></th>
                </tr>
                </thead>
                <tbody>
                <tr ng-repeat="data in StudentRecorddata">
                    <td>{{data.Name}}</td>
                    <td>{{data.Eduction}}</td>
                    <td>{{data.Email}} </td>
                    <td><button type="button" class="btn btn-info" ui-sref="Setting.StudenListing.StudentList({StudentID:$index})">View Details</button> </td>
                </tr>

                </tbody>
            </table>
        </div>
        <div class="col-sm-6" style="background-color:beige;">
           <!-- <div ui-view="StudenListing"></div>-->
            <div ui-view="StudentDetails"></div>
        </div>
    </div>
=================================================================================
-- studentDetails.html
------------------------------------------------------------------------------<div>
    <h2>Student Details </h2>
    <br>
    <form class="form-horizontal">
        <div class="form-group">
            <label class="control-label col-sm-2" for="email">Stuent Id:</label>
            <div class="col-sm-10">
                <p class="form-control-static">{{StudentID}}</p>
            </div>
        </div>
        <div class="form-group">
           <label class="control-label col-sm-2" for="email">Name:</label>
            <div class="col-sm-10">
                <p class="form-control-static">{{StuentDetails.Name}}</p>
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-sm-2" for="pwd">Age:</label>
            <div class="col-sm-10">
                <p class="form-control-static">{{StuentDetails.Age}}</p>
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-sm-2" for="email">Eduction:</label>
            <div class="col-sm-10">
                <p class="form-control-static">{{StuentDetails.Eduction}}</p>
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-sm-2" for="pwd">Email:</label>
            <div class="col-sm-10">
                <p class="form-control-static">{{StuentDetails.Email}}</p>
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-sm-2" for="email">MobileNumber:</label>
            <div class="col-sm-10">
                <p class="form-control-static">{{StuentDetails.MobileNumber}}</p>
            </div>
        </div>
        <div class="form-group">
            <label class="control-label col-sm-2" for="pwd">Gender:</label>
            <div class="col-sm-10">
                <p class="form-control-static">{{StuentDetails.Gender}}</p>
            </div>
        </div>

    </form>
</div>
like image 537
Sumit patel Avatar asked Jan 02 '17 06:01

Sumit patel


People also ask

How to redirect page not found errors to a page in ExpressJS?

In Express if we want to redirect the user to the 404 error page if a particular route does not exist then we can use the app. all() method as the last route handler method and * (asterisk) as the route name.

How to handle 404 error in Express?

All you need to do is add a middleware function at the very bottom of the stack (below all other functions) to handle a 404 response: app. use((req, res, next) => { res. status(404).


2 Answers

This is because the web server receiving the request looks for a resource matching the full url on the server, which doesn't exist because the angular portion of the url refers to a route in your angular application and needs to be handled in the client browser

The way to fix this is by rewriting all virtual urls to the main angular index.html file

AngularJS + NodeJS/ExpressJS - Routes to prevent 404 error after page refresh in html5mode

var express = require('express');
var path = require('path');
var router = express.Router();

// serve angular front end files from root path
router.use('/', express.static('app', { redirect: false }));

// rewrite virtual urls to angular app to enable refreshing of internal pages
router.get('*', function (req, res, next) {
    res.sendFile(path.resolve('app/index.html'));
});

module.exports = router;

AngularJS + IIS - URL Rewrite Rule to prevent 404 error after page refresh in html5mode (for apache click here)

<rewrite>
  <rules>
    <rule name="AngularJS" stopProcessing="true">
      <match url=".*" />
      <conditions logicalGrouping="MatchAll">
        <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
        <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
      </conditions>
      <action type="Rewrite" url="/" />
    </rule>
  </rules>
</rewrite>

Referred from

additional way to fix this

https://stackoverflow.com/a/34817349/2218635

like image 111
Ramesh Rajendran Avatar answered Oct 22 '22 02:10

Ramesh Rajendran


This is what I have for my app.

From the API docs for HTML5 mode

if (HTML5 mode is) enabled and requireBase are true, and a base tag is not present, an error will be thrown when $location is injected.

So, you need the base tag. I've tried without the base tag and requireBase to be false but it still seems to throw an error for me.

index.html

<head>
    <base href="/">
</head>

app.route.js[Angular.js]

app.config(function($stateProvider, $urlRouterProvider, $locationProvider) {

    // This removes '#' and makes URL pretty
    $locationProvider.html5Mode({
        enabled: true,
        requireBase: true
    });

    // Default path if nothing is matched. State would become 'landing'
    $urlRouterProvider.otherwise('/');

    $stateProvider
        .state('landing', {
            url: '/',
            templateUrl: "/dashboard/landing/templates/index.html",
            controller: 'LandingController'
        }).state('about', {
            url: '/about',
            templateUrl: "/dashboard/about/templates/index.html",
            controller: 'AboutController'
        });

});

Once you redirect yourself from 'landing' to 'about' state and the route changes to /about, the URL is only changed on the browser and the server does not know of this. So, when you refresh, the server does not know what /about path means. Thus, you need to redirect /about path (or any path that belongs to angular's routes) to index.html and then angular redirects you back to /about automagically.

app.js[Express.js]

//  dashboard route should deliver templates instead of loading angular JS app so this should come before the next one
app.use('/dashboard', express.static(__dirname + '/public/dashboard'));

// put all the API methods here and separate from the redirection to `index.html`
app.use('/api', routes.apiRoutes); 

// all the paths that do not start with `/dashboard` or `/api` is/should be angular route and thus, redirect back to `index.html`
app.get('*', function (req, res) {
    res.sendFile(__dirname + '/public/index.html');
});

Side note

On another app, I've seen an issue where refreshing the browser appends a trailing slash at the end of the path (/) and after the redirection, Angular app could not recognize the path from the url /about vs /about/ so it redirected me back to the landing page.

I resolved this by adding this in app.route.js

$urlMatcherFactoryProvider.strictMode(false);

I hope this helps

like image 21
Taku Avatar answered Oct 22 '22 00:10

Taku