Le rechargement de la page donne une requête GET erronée avec le mode AngularJS HTML5
je veux 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 voir, j'ai utilisé le $locationProvider.html5mode
et j'ai changé 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 je rafraîchis la page localhost:9000/about
. Je reçois la sortie suivante: Cannot GET /about
si je regarde les appels réseau:
Request URL:localhost:9000/about
Request Method:GET
alors que si je vais d'abord à localhost:9000/
et puis cliquez sur un bouton qui navigue à /about
je comprends:
Request URL:http://localhost:9000/views/about.html
qui rend la page parfaitement.
Comment puis-je activer angular pour obtenir la page correcte quand je rafraîchis?
24 réponses
De la angulaire docs
Côté Serveur
L'utilisation de ce mode nécessite la réécriture D'URL côté serveur, fondamentalement, vous devez réécrire tous vos liens au point d'entrée de votre application (par exemple index.html)
la raison en est que lorsque vous visitez pour la première fois la page ( /about
), par exemple après un rafraîchissement, le navigateur n'a aucun moyen de savoir que ce N'est pas une vraie URL, donc il va de l'avant et le charge. Cependant, si vous avez chargé la page racine d'abord, et tout le code javascript, puis lorsque vous naviguez à /about
Angular peut y entrer avant que le navigateur tente de frapper le serveur et de gérer en conséquence
il y a peu de choses à configurer de sorte que votre lien dans le navigateur ressemblera à http://yourdomain.com/path
et ce sont 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 coller ce
RewriteEngine On
Options FollowSymLinks
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /#/ [L]
choses plus intéressantes à lire sur le mode HTML5 en angularjs et la configuration requise selon l'environnement https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions#how-to-configure-your-server-to-work-with-html5mode Aussi cette question pourrait vous aider à $emplacement / commutation entre html5 et hashbang mode / lien réécriture
j'ai eu un problème similaire et je l'ai résolu en:
-
utilisant
<base href="/index.html">
dans la page d'index -
utilisant un middleware catch all route dans mon serveur node/Express comme suit (mettez-le après le routeur):
app.use(function(req, res) {
res.sendfile(__dirname + '/Public/index.html');
});
je pense que ça devrait te mettre en route.
Si vous utilisez un serveur apache, vous pouvez mod_rewrite vos liens. Il n'est pas difficile à faire. Quelques modifications dans les fichiers de configuration.
tout ce qui suppose que vous avez html5mode activé sur angularjs. Maintenant. notez que dans l'angle 1.2, déclarer une url de base n'est plus recommandé.
Solution pour BrowserSync et Gulfp.
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
puis ajoutez-le à votre gulffile.js:
var historyApiFallback = require('connect-history-api-fallback');
gulp.task('serve', function() {
browserSync.init({
server: {
baseDir: "app",
middleware: [ historyApiFallback() ]
}
});
});
vous devez configurer votre serveur pour réécrire tout à index.html pour charger l'application:
j'ai écrit un simple middleware 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)
];
}
}
}
}
})
};
si vous êtes dans la pile .NET avec MVC avec AngularJS, c'est ce que vous devez faire pour supprimer le ' # 'de l'url:
-
"installez votre base href dans votre page _Layout:
<head> <base href="/"> </head>
-
ensuite, ajouter ce qui suit dans votre configuration de l'application angulaire:
$locationProvider.html5Mode(true)
-
ci-dessus supprimera' # ' de l'url mais le rafraîchissement de la page ne fonctionnera pas, par exemple si vous êtes dans "yoursite.com/about" page refresh vous donnera un 404. Ceci est dû au fait que MVC ne connaît pas le routage angulaire et que par MVC pattern il va chercher une page MVC pour 'about' qui n'existe pas dans le chemin D'acheminement MVC. La solution pour cela est d'envoyer toutes les requêtes de page MVC à une seule vue MVC et vous pouvez le faire en ajoutant une route qui capture toutes les url
routes.MapRoute(
name: "App",
url: "{*url}",
defaults: new { controller = "Home", action = "Index" }
);
IIS Règle de Réécriture d'URL pour prévenir erreur 404 après actualisation de la page dans html5mode
angulaire de l'exécution sous IIS sur 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 prévenir erreur 404 après actualisation de la page dans html5mode
pour course angulaire sous noeud / 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'informations à: AngularJS-Enable HTML5 Mode Mise à jour de la Page sans 404 erreurs dans NodeJS et IIS
comme d'autres l'ont mentionné, vous devez réécrire les routes sur le serveur et mettre <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()
];
}
...
})
....
j'utilise apache (xampp) sur mon environnement dev et apache sur la production, ajouter:
errorDocument 404 /index.html
à la .htaccess résout pour moi ce problème.
j'ai résolu en
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')
];
}
}
},
je réponds à cette question à partir de la grande question:
quand j'ajoute $locationProvider.html5Mode (true), mon site ne permettra pas le collage d'urls. Comment configurer mon serveur pour qu'il fonctionne quand html5mode est true?
lorsque vous avez html5mode activé, le caractère # ne sera plus utilisé dans vos urls. Le symbole # est utile car il ne nécessite aucune configuration côté serveur. Sans #, l'url semble beaucoup plus agréable, mais il nécessite également des réécritures côté serveur. Voici quelques exemples:
pour les réécritures Express avec AngularJS, vous pouvez résoudre cela 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'));
Pour Grognement et Browsersync utilisation connectez-modrewrite ici
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
}
}
}
},
je crois que votre problème concerne le serveur. La documentation angulaire concernant le mode HTML5 (au lien de votre question) indique:
Côté Serveur L'utilisation de ce mode nécessite la réécriture D'URL côté serveur, fondamentalement, vous devez réécrire tous vos liens au 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 /about à /.
nous avions un serveur redirect dans Express:
app.get('*', function(req, res){
res.render('index');
});
et nous avions encore des problèmes de rafraîchissement de page, même après avoir ajouté le <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 page-refresh. (stupide erreur, je sais)
: - P
enfin j'ai trouvé un moyen de résoudre ce problème côté serveur car C'est plus comme un problème avec AngularJs lui-même j'utilise 1,5 Angularjs et j'ai eu le même problème sur recharger la page.
Mais après avoir ajouté le code ci-dessous dans mon server.js
fichier, il est enregistrer mon jour mais ce n'est pas une bonne solution ou pas une bonne façon .
app.use(function(req, res, next){
var d = res.status(404);
if(d){
res.sendfile('index.html');
}
});
j'ai trouvé encore mieux Grunt plugin, qui fonctionne si vous avez votre 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)
];
}
},
}
},
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
});
}
j'ai eu le même problème avec java + angulaire de l'application générée avec JHipster . Je l'ai résolu avec le filtre et la liste de toutes les pages angulaires dans les propriétés:
de l'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);
}
Espère que ce sera utile pour quelqu'un.
Gulp + browserSync:
Installer connectez-histoire-api-secours via npm, plus tard config à votre service gulp tâche
var historyApiFallback = require('connect-history-api-fallback');
gulp.task('serve', function() {
browserSync.init({
proxy: {
target: 'localhost:' + port,
middleware: [ historyApiFallback() ]
}
});
});
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
Etape 2: Activer HTML5 Mode $locationProvider.html5Mode (true);
étape 3: Définir L'URL de base <base href="/example.com/"/>
étape 4: copier-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 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>
j'ai cette solution simple que j'ai utilisé et ses travaux.
Dans App/Exceptions/Gestionnaire.php
ajouter à la fin:
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);
}
j'ai résolu le problème en ajoutant ci-dessous le code snippet dans le noeud.fichier js.
app.get("/*", function (request, response) {
console.log('Unknown API called');
response.redirect('/#' + request.url);
});
Note: Lorsque nous rafraîchissons la page, elle recherche 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 #
il suffit d'écrire une règle dans le web.config
<system.webServer>
<rewrite>
<rules>
<rule name="AngularJS Routes" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
dans l'index ajouter ce
<base href="/">
ça marche pour moi peut-être que vous avez oublié de configurer l'application Html5Mode.config
app.config(function ($stateProvider, $urlRouterProvider, $locationProvider){
$locationProvider.html5Mode({ enabled: true, requireBase: true });
$locationProvider.hashPrefix('!');
}