web-dev-qa-db-fra.com

Le rechargement de la page donne une mauvaise requête GET avec le mode AngularJS HTML5

Je souhaite activer le mode HTML5 pour mon application. J'ai mis le code suivant pour la configuration, comme indiqué ici :

return app.config(['$routeProvider','$locationProvider', function($routeProvider,$locationProvider) {

    $locationProvider.html5Mode(true);
    $locationProvider.hashPrefix = '!';

    $routeProvider.when('/', {
        templateUrl: '/views/index.html',
        controller: 'indexCtrl'
    });
    $routeProvider.when('/about',{
        templateUrl: '/views/about.html',
        controller: 'AboutCtrl'
    });

Comme vous pouvez le constater, j’ai utilisé le $locationProvider.html5mode et j’ai modifié tous mes liens au ng-href pour exclure le /#/.

Le problème

Pour le moment, je peux aller à localhost:9000/ et voir la page d'index et naviguer vers les autres pages comme localhost:9000/about

Cependant, le problème se produit lorsque j'actualise la page localhost:9000/about. Je reçois le résultat suivant: Cannot GET /about

Si je regarde les appels réseau:

Request URL:localhost:9000/about
Request Method:GET

Tandis que si je vais d’abord à localhost:9000/ puis que je clique sur un bouton qui permet de naviguer vers /about j’obtiens:

Request URL:http://localhost:9000/views/about.html

Ce qui rend la page parfaitement. 

Comment puis-je activer angular pour obtenir la page correcte lors de l'actualisation?

190

De la docs angulaires

Du côté serveur
L'utilisation de ce mode nécessite une réécriture d'URL côté serveur. En gros, vous devez réécrire tous vos liens vers le point d'entrée de votre application (par exemple, index.html).

La raison en est que lorsque vous visitez la page pour la première fois (/about), par exemple. après une actualisation, le navigateur n'a aucun moyen de savoir qu'il ne s'agit pas d'une URL réelle, il le charge ensuite. Cependant, si vous avez d'abord chargé la page racine et tout le code javascript, vous pouvez accéder à /about Angular avant que le navigateur n'essaye de frapper le serveur et de le gérer en conséquence.

98
James Sharp

Il y a peu de choses à configurer pour que votre lien dans le navigateur ressemble à http://yourdomain.com/path et qu'il s'agit de votre configuration angulaire + côté serveur

1) AngularJS

$routeProvider
  .when('/path', {
    templateUrl: 'path.html',
  });
$locationProvider
  .html5Mode(true);

2) côté serveur, il suffit de mettre .htaccess dans votre dossier racine et de le coller

RewriteEngine On 
Options FollowSymLinks

RewriteBase /

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /#/$1 [L]

Autres informations intéressantes sur le mode html5 dans angularjs et la configuration requise pour différents environnements https://github.com/angular-ui/ui-router/wiki/Frequent-Asked-Questions#how-to-configure-votre -server-to-work-with-html5mode Cette question pourrait également vous aider $ location/basculer entre html5 et le mode hashbang/réécriture de liens

61
lokers

J'ai eu un problème similaire et je l'ai résolu par: 

  • Utilisation de <base href="/index.html"> dans la page d'index

  • Utiliser un intergiciel de routage attrape-route dans mon nœud/serveur Express comme suit (mettez-le après le routeur):

app.use(function(req, res) {
    res.sendfile(__dirname + '/Public/index.html');
});

Je pense que cela devrait vous permettre de démarrer.

Si vous utilisez un serveur Apache, vous pouvez vouloir mod_rewrite vos liens. Ce n'est pas difficile à faire. Juste quelques changements dans les fichiers de configuration.

Tout cela en supposant que vous avez activé html5mode sur angularjs . Maintenant. notez que dans la version 1.2 angulaire, déclarer une URL de base n’est plus recommandé.

34
Taye

Solution pour BrowserSync et Gulp.

De https://github.com/BrowserSync/browser-sync/issues/204#issuecomment-102623643

Première installation connect-history-api-fallback:

npm --save-dev install connect-history-api-fallback

Ajoutez-le ensuite à votre fichier gulpfile.js:

var historyApiFallback = require('connect-history-api-fallback');

gulp.task('serve', function() {
  browserSync.init({
    server: {
      baseDir: "app",
      middleware: [ historyApiFallback() ]
    }
  });
});
26
Oscar

Vous devez configurer votre serveur pour qu'il réécrit tout en index.html afin de charger l'application:

https://github.com/angular-ui/ui-router/wiki/Frequent-Asked-Questions#wiki-how-to-configure-your-server-to-work-with-html5mode

13
grant

J'ai écrit un middleware simple Connect pour simuler la réécriture d'URL sur des projets Grunt. https://Gist.github.com/muratcorlu/5803655

Vous pouvez utiliser comme ça:

module.exports = function(grunt) {
  var urlRewrite = require('grunt-connect-rewrite');

  // Project configuration.
  grunt.initConfig({
    connect: {
      server: {
        options: {
          port: 9001,
          base: 'build',
          middleware: function(connect, options) {
            // Return array of whatever middlewares you want
            return [
              // redirect all urls to index.html in build folder
              urlRewrite('build', 'index.html'),

              // Serve static files.
              connect.static(options.base),

              // Make empty directories browsable.
              connect.directory(options.base)
            ];
          }
        }
      }
    }
  })
};
10
Murat Çorlu

Si vous êtes dans la pile .NET avec MVC avec AngularJS, voici ce que vous devez faire pour supprimer le "#" de l'URL: 

  1. Configurez votre href de base dans votre page _Layout: <head> <base href="/"> </head>

  2. Ensuite, ajoutez ce qui suit dans votre configuration d'application angulaire: $locationProvider.html5Mode(true)

  3. Ci-dessus supprimera "#" de l'URL mais l'actualisation de la page ne fonctionnera pas, par exemple. si vous vous trouvez dans "yoursite.com/about", l'actualisation vous en donnera un 404. En effet, MVC ne connaît pas le routage angulaire et, par modèle MVC, il recherchera une page MVC pour "à propos de" qui n'existe pas dans MVC. chemin de routage. La solution consiste à envoyer toutes les demandes de page MVC à une seule vue MVC. Pour ce faire, vous pouvez ajouter un itinéraire qui capture toutes les URL.


routes.MapRoute(
        name: "App",
        url: "{*url}",
        defaults: new { controller = "Home", action = "Index" }
    );
8
Maksood

IIS règle de réécriture d'URL pour empêcher l'erreur 404 après l'actualisation de page en html5mode

Pour l'exécution angulaire sous IIS sous Windows

<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>

NodeJS/ExpressJS Routes pour éviter l'erreur 404 après l'actualisation de la page en html5mode

Pour l'exécution angulaire sous Node/Express

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;

Plus d'infos sur: AngularJS - Activer l'actualisation de la page en mode HTML5 sans erreur 404 dans NodeJS et IIS

8
Jason

Comme d'autres l'ont mentionné, vous devez réécrire les itinéraires sur le serveur et définir <base href="/"/>.

Pour gulp-connect:

npm install connect-pushstate

var gulp = require('gulp'),
  connect = require('gulp-connect'),
  pushState = require('connect-pushstate/lib/pushstate').pushState;
...
connect.server({
  ...
  middleware: function (connect, options) {
    return [
      pushState()
    ];
  }
  ...
})
....
5
Brett

J'utilise Apache (xampp) sur mon environnement de développement et Apache sur la production, Ajouter:

errorDocument 404 /index.html

au .htaccess résoudre pour moi ce problème.

4
crlshn

J'ai résolu de 

test: {
        options: {
          port: 9000,
          base: [
            '.tmp',
            'test',
            '<%= yeoman.app %>'
          ],
         middleware: function (connect) {
                  return [
                      modRewrite(['^[^\\.]*$ /index.html [L]']),
                      connect.static('.tmp'),
                      connect().use(
                          '/bower_components',
                          connect.static('./bower_components')
                      ),
                      connect.static('app')
                  ];
              }
        }
      },
3
Silvio Troia

Je réponds à cette question de la plus grande question:

Lorsque j'ajoute $ locationProvider.html5Mode (true), mon site n'autorise pas le collage des URL. Comment configurer mon serveur pour qu'il fonctionne lorsque html5Mode est à true?

Lorsque vous avez activé html5Mode, le caractère # ne sera plus utilisé dans vos URL. Le symbole # est utile car il ne nécessite aucune configuration côté serveur. Sans #, l'URL est beaucoup plus jolie, mais elle nécessite également des réécritures côté serveur. Voici quelques exemples:

Pour Express Rewrites avec AngularJS, vous pouvez résoudre ce problème avec les mises à jour suivantes:

app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname + '/public/app/views/index.html'));
});

et 

<!-- FOR ANGULAR ROUTING -->
<base href="/">

et

app.use('/',express.static(__dirname + '/public'));
3
Ironheartbj18

Pour Grunt et Browsersync, utilisez connect-modrewrite here

var modRewrite = require('connect-modrewrite');    


browserSync: {
            dev: {
                bsFiles: {

                    src: [
                        'app/assets/css/*.css',
                        'app/*.js',
                        'app/controllers/*.js',
                        '**/*.php',
                        '*.html',
                        'app/jade/includes/*.jade',
                        'app/views/*.html',
               ],
            },
        options: {
            watchTask: true,
            debugInfo: true,
            logConnections: true,
            server: {
                baseDir :'./',
                middleware: [
                       modRewrite(['!\.html|\.js|\.jpg|\.mp4|\.mp3|\.gif|\.svg\|.css|\.png$ /index.html [L]'])
                ]
            },

            ghostMode: {
                scroll: true,
                links: true,
                forms: true
                    }
                }
            }
        },
3
MrThunder

Je crois que votre problème concerne le serveur. La documentation angulaire relative au mode HTML5 (sur le lien de votre question) indique:

Côté serveur L'utilisation de ce mode nécessite la réécriture d'URL côté serveur, vous devez donc réécrire tous vos liens vers le point d'entrée de votre application (par exemple, index.html).

Je crois que vous aurez besoin de configurer une réécriture d'URL de/sur à /.

2
lucuma

Nous avons eu une redirection de serveur dans Express:

app.get('*', function(req, res){
    res.render('index');
});

et nous avions toujours des problèmes d’actualisation de la page, même après l’ajout du <base href="/" />.

Solution: assurez-vous que vous utilisez des liens réels dans votre page pour naviguer; ne tapez pas la route dans l'URL ou vous obtiendrez une actualisation de la page. (erreur stupide, je sais)

:-P

2
Cody

Enfin, j’ai un moyen de résoudre ce problème côté serveur car c’est plutôt un problème avec AngularJs lui-même, j’utilise 1.5 Angularjs et j’ai le même problème lors du rechargement de la page . Mais après avoir ajouté le code ci-dessous dans mon server.js, le déposer est sauver ma journéemais ce n'est pas une solution appropriée ou un bon moyen.

app.use(function(req, res, next){
  var d = res.status(404);
     if(d){
        res.sendfile('index.html');
     }
});
1
Anil Yadav

J'ai cette solution simple que j'utilise et ses travaux.

Dans l'application/Exceptions/Handler.php

Ajoutez ceci en haut:

use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

Puis à l'intérieur de la méthode de rendu

public function render($request, Exception $exception)
{
    .......

       if ($exception instanceof NotFoundHttpException){

        $segment = $request->segments();

        //eg. http://site.dev/member/profile
        //module => member
        // view => member.index
        //where member.index is the root of your angular app could be anything :)
        if(head($segment) != 'api' && $module = $segment[0]){
            return response(view("$module.index"), 404);
        }

        return response()->fail('not_found', $exception->getCode());

    }
    .......

     return parent::render($request, $exception);
}
0
Digitlimit

J'ai eu le même problème avec Java + application angulaire générée avec JHipster . Je l'ai résolu avec Filtre et liste de toutes les pages angulaires dans les propriétés: 

application.yml:

angular-pages:
  - login
  - settings
...

AngularPageReloadFilter.Java

public class AngularPageReloadFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        request.getRequestDispatcher("index.html").forward(request, response);
    }
}

WebConfigurer.Java

private void initAngularNonRootRedirectFilter(ServletContext servletContext,
                                              EnumSet<DispatcherType> disps) {
    log.debug("Registering angular page reload Filter");
    FilterRegistration.Dynamic angularRedirectFilter =
            servletContext.addFilter("angularPageReloadFilter",
                    new AngularPageReloadFilter());
    int index = 0;
    while (env.getProperty("angular-pages[" + index + "]") != null) {
        angularRedirectFilter.addMappingForUrlPatterns(disps, true, "/" + env.getProperty("angular-pages[" + index + "]"));
        index++;
    }
    angularRedirectFilter.setAsyncSupported(true);
}

J'espère que ce sera utile pour quelqu'un.

0
Igor Zboichik

Gulp + browserSync:

Installez connect-history-api-fallback via npm, puis configurez votre tâche serve gulp

var historyApiFallback = require('connect-history-api-fallback');

gulp.task('serve', function() {
  browserSync.init({
    proxy: {
            target: 'localhost:' + port,
            middleware: [ historyApiFallback() ]
        }
  });
});
0
Oscar Caicedo

J'ai trouvé encore mieux le plugin Grunt, cela fonctionne si vous avez index.html et Gruntfile.js dans le même répertoire;

https://npmjs.org/package/grunt-connect-pushstate

Après cela dans votre Gruntfile:

 var pushState = require('grunt-connect-pushstate/lib/utils').pushState;


    connect: {
    server: {
      options: {
        port: 1337,
        base: '',
        logger: 'dev',
        hostname: '*',
        open: true,
        middleware: function (connect, options) {
          return [
            // Rewrite requests to root so they may be handled by router
            pushState(),
            // Serve static files
            connect.static(options.base)
          ];
        }
      },
    }
},
0
Michał Lach
I solved same problem using modRewrite.  
AngularJS is reload page when after # changes.  
But HTML5 mode remove # and invalid the reload.  
So we should reload manually.
# install connect-modrewrite
    $ Sudo npm install connect-modrewrite --save

# gulp/build.js
    'use strict';
    var gulp = require('gulp');
    var paths = gulp.paths;
    var util = require('util');
    var browserSync = require('browser-sync');
    var modRewrite  = require('connect-modrewrite');
    function browserSyncInit(baseDir, files, browser) {
        browser = browser === undefined ? 'default' : browser;
        var routes = null;
        if(baseDir === paths.src || (util.isArray(baseDir) && baseDir.indexOf(paths.src) !== -1)) {
            routes = {
                '/bower_components': 'bower_components'
            };
        }

        browserSync.instance = browserSync.init(files, {
            startPath: '/',
            server: {
            baseDir: baseDir,
            middleware: [
                modRewrite([
                    '!\\.\\w+$ /index.html [L]'
                ])
            ],
            routes: routes
            },
            browser: browser
        });
    }
0
keiwt

Votre code côté serveur est Java, puis suivez les étapes ci-dessous.

étape 1: Télécharger urlrewritefilter JAR Cliquez ici et sauvegarder pour construire le chemin WEB-INF/lib

étape 2: Activer le mode HTML5 $ locationProvider.html5Mode (true);

étape 3: définir l'URL de base <base href="/example.com/"/>

étape 4: copier et coller sur votre WEB.XML 

 <filter>
     <filter-name>UrlRewriteFilter</filter-name>
 <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>UrlRewriteFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

étape 5: créer un fichier dans WEN-INF/urlrewrite.xml

 <urlrewrite default-match-type="wildcard">


    <rule>
            <from>/</from>
            <to>/index.html</to>
        </rule>

    <!--Write every state dependent on your project url-->
    <rule>
            <from>/example</from>
            <to>/index.html</to>
        </rule>
    </urlrewrite>
0
senthil raja

J'ai résolu le problème en ajoutant l'extrait de code ci-dessous dans le fichier node.js.

app.get("/*", function (request, response) {
    console.log('Unknown API called');
    response.redirect('/#' + request.url);
});

Remarque: lorsque nous actualisons la page, elle recherchera l'API au lieu de la page angulaire (en raison de l'absence de balise # dans l'URL.). En utilisant le code ci-dessus, je redirige vers l’url avec #

0
Ram Gollapalli