Перезагрузка страницы дает неверный запрос GET в режиме AngularJS HTML5
Я хочу включить режим HTML5 для моего приложения. Я поставил следующий код для конфигурации, как показано здесь:
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'
});
Как видите, я использовал $locationProvider.html5mode
и я изменил все свои ссылки на ng-href
исключить /#/
,
Эта проблема
На данный момент я могу пойти в localhost:9000/
и увидеть страницу индекса и перейти к другим страницам, как localhost:9000/about
,
Однако проблема возникает, когда я обновляю localhost:9000/about
стр. Я получаю следующий вывод: Cannot GET /about
Если я смотрю на сетевые звонки:
Request URL:localhost:9000/about
Request Method:GET
Хотя если я впервые пойду localhost:9000/
а затем нажмите на кнопку, которая перемещается к /about
Я получил:
Request URL:http://localhost:9000/views/about.html
Который отрисовывает страницу отлично.
Как я могу включить Angular для получения правильной страницы при обновлении?
24 ответа
Серверная сторона
Использование этого режима требует перезаписи URL на стороне сервера, в основном вам нужно переписать все ваши ссылки на точку входа вашего приложения (например, index.html)
Причина этого заключается в том, что при первом посещении страницы (/about
), например, после обновления браузер не может узнать, что это не настоящий URL, поэтому он загружает его. Однако если вы сначала загрузили корневую страницу и весь код javascript, то при переходе к /about
Angular может войти туда до того, как браузер попытается поразить сервер и обработать его соответствующим образом.
Есть несколько вещей, которые нужно настроить, чтобы ваша ссылка в браузере была похожа http://yourdomain.com/path
а это ваш угловой конфиг + серверная сторона
1) AngularJS
$routeProvider
.when('/path', {
templateUrl: 'path.html',
});
$locationProvider
.html5Mode(true);
2) серверная сторона, просто поставь .htaccess
внутри вашей корневой папки и вставьте это
RewriteEngine On
Options FollowSymLinks
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /#/$1 [L]
Более интересные материалы для чтения о режиме html5 в angularjs и конфигурации, требуемой для разных сред https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions Также этот вопрос может помочь вам $location / переключения между html5 и режимом hashbang / переписыванием ссылок
У меня была похожая проблема, и я решил ее:
С помощью
<base href="/index.html">
на странице указателяИспользуя промежуточное ПО перехвата всех маршрутов на моем узле / сервере Express следующим образом (поместите его после маршрутизатора):
app.use(function(req, res) {
res.sendfile(__dirname + '/Public/index.html');
});
Я думаю, что это должно заставить вас работать.
Если вы используете сервер Apache, вы можете захотеть mod_rewrite ваши ссылки. Это не сложно сделать. Всего несколько изменений в конфигурационных файлах.
Все, что предполагает наличие html5mode в angularjs. Сейчас. обратите внимание, что в угловых 1.2 объявление базового URL больше не рекомендуется на самом деле.
Решение для BrowserSync и Gulp.
С https://github.com/BrowserSync/browser-sync/issues/204
Первая установка connect-history-api-fallback
:
npm --save-dev install connect-history-api-fallback
Затем добавьте его в свой gulpfile.js:
var historyApiFallback = require('connect-history-api-fallback');
gulp.task('serve', function() {
browserSync.init({
server: {
baseDir: "app",
middleware: [ historyApiFallback() ]
}
});
});
Вам нужно настроить свой сервер так, чтобы все переписывалось в index.html для загрузки приложения:
https://github.com/angular-ui/ui-router/wiki/Frequently-Asked-Questions
Я написал простое промежуточное ПО для подключения, имитирующее переписывание URL-адресов в проектах grunt. https://gist.github.com/muratcorlu/5803655
Вы можете использовать так:
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)
];
}
}
}
}
})
};
Если вы находитесь в стеке.NET с MVC с AngularJS, это то, что вам нужно сделать, чтобы удалить '#' из URL:
Настройте ваш базовый href на странице _Layout:
<head> <base href="/"> </head>
Затем добавьте следующее в конфигурацию вашего углового приложения:
$locationProvider.html5Mode(true)
Выше удалит "#" из URL, но обновление страницы не будет работать, например, если вы находитесь на странице "yoursite.com/about", обновление даст вам 404. Это потому, что MVC не знает об угловой маршрутизации и по шаблону MVC это будет искать страницу MVC для 'about', которой нет в пути маршрутизации MVC. Обходным путем для этого является отправка всех запросов страниц MVC в одно представление MVC, и вы можете сделать это, добавив маршрут, который перехватывает все URL-адреса.
routes.MapRoute(
name: "App",
url: "{*url}",
defaults: new { controller = "Home", action = "Index" }
);
Правило перезаписи URL IIS для предотвращения ошибки 404 после обновления страницы в html5mode
Для углового запуска под IIS в 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 Маршруты для предотвращения ошибки 404 после обновления страницы в html5mode
Для углового бега под 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;
Дополнительная информация: AngularJS - включить обновление страницы в режиме HTML5 без ошибок 404 в NodeJS и IIS
Как уже упоминали другие, вам нужно переписать маршруты на сервере и установить <base href="/"/>
,
За 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()
];
}
...
})
....
Для Grunt и Browsersync используйте connect-modrewrite здесь
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
}
}
}
},
Я использую apache (xampp) в своей среде разработки и apache на производстве, добавьте:
errorDocument 404 /index.html
.htaccess решить для меня эту проблему.
Я отвечаю на этот вопрос из более крупного вопроса:
Когда я добавляю $locationProvider.html5Mode(true), мой сайт не позволяет вставлять URL-адреса. Как мне настроить мой сервер для работы, когда html5Mode имеет значение true?
Когда у вас включен html5Mode, символ # больше не будет использоваться в ваших URL. Символ # полезен, поскольку не требует настройки на стороне сервера. Без # URL выглядит намного лучше, но это также требует переписывания на стороне сервера. Вот некоторые примеры:
Для Express Rewrites с AngularJS вы можете решить эту проблему с помощью следующих обновлений:
app.get('/*', function(req, res) {
res.sendFile(path.join(__dirname + '/public/app/views/index.html'));
});
а также
<!-- FOR ANGULAR ROUTING -->
<base href="/">
а также
app.use('/',express.static(__dirname + '/public'));
Я решил
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')
];
}
}
},
Я считаю, что ваша проблема связана с сервером. В англоязычной документации по режиму HTML5 (по ссылке в вашем вопросе) говорится:
На стороне сервера Для использования этого режима требуется перезапись URL на стороне сервера, в основном вам нужно переписать все ваши ссылки на точку входа вашего приложения (например, index.html).
Я считаю, что вам нужно настроить переписать URL-адрес с / о /.
У нас был сервер перенаправления в Express:
app.get('*', function(req, res){
res.render('index');
});
и у нас все еще возникали проблемы с обновлением страницы, даже после того, как мы добавили <base href="/" />
,
Решение: убедитесь, что вы используете реальные ссылки на своей странице для навигации; не вводите маршрут в URL, иначе вы получите обновление страницы. (глупая ошибка, я знаю)
:-П
Наконец-то у меня появился способ решить эту проблему на стороне сервера, так как это больше похоже на проблему с самими AngularJ, я использую 1.5 Angularjs и у меня возникла такая же проблема при перезагрузке страницы. Но после добавления кода ниже в моем server.js
Файл это сохранить мой день, но это не правильное решение или не хороший способ.
app.use(function(req, res, next){
var d = res.status(404);
if(d){
res.sendfile('index.html');
}
});
Я решил проблему, добавив приведенный ниже фрагмент кода в файл node.js.
app.get("/*", function (request, response) {
console.log('Unknown API called');
response.redirect('/#' + request.url);
});
Примечание: когда мы обновляем страницу, она будет искать API вместо страницы Angular (из-за отсутствия тега # в URL.) . Используя приведенный выше код, я перенаправляю на URL с #
У меня была такая же проблема с приложением java + angular, созданным с помощью JHipster. Я решил это с помощью фильтра и списка всех угловых страниц в свойствах:
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);
}
Надеюсь, это будет полезно для кого-то.
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
});
}
У меня есть это простое решение, которое я использую, и оно работает.
В приложении /Exceptions/Handler.php
Добавьте это вверху:
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
Затем внутри метода рендера
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);
}
Gulp + browserSync:
Установите connect-history-api-fallback через npm, позже сконфигурируйте свою задачу подачи gulp
var historyApiFallback = require('connect-history-api-fallback');
gulp.task('serve', function() {
browserSync.init({
proxy: {
target: 'localhost:' + port,
middleware: [ historyApiFallback() ]
}
});
});
Ваш код на стороне сервера - JAVA, затем выполните следующие шаги
Шаг 1: Загрузите JAR urlrewritefilter. Нажмите здесь и сохраните, чтобы построить путь. WEB-INF/lib
шаг 2: включить режим HTML5 $locationProvider.html5Mode(true);
шаг 3: установить базовый URL <base href="/example.com/"/>
шаг 4: скопируйте и вставьте в свой 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>
Шаг 5: создайте файл в 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>
Я нашел даже лучший плагин Grunt, который работает, если у вас есть index.html и Gruntfile.js в одном каталоге;
https://npmjs.org/package/grunt-connect-pushstate
После этого в вашем 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)
];
}
},
}
},
Просто напишите правило в 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>
В индекс добавить это
<base href="/">
это работает для меня, может быть, вы забыли установить Html5Mode app.config
app.config(function ($stateProvider, $urlRouterProvider, $locationProvider){
$locationProvider.html5Mode({ enabled: true, requireBase: true });
$locationProvider.hashPrefix('!');
}