Перезагрузка страницы дает неверный запрос GET в режиме AngularJS HTML5

193

Я хочу включить режим 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 для получения правильной страницы при обновлении?

Дитер де Месмакер
источник
Смотрите здесь stackoverflow.com/questions/22394014/…
Саша Б.
1
Я решаю это для себя. Смотрите здесь stackoverflow.com/questions/22394014/…
Саша Б.

Ответы:

99

Из угловых документов

На стороне сервера Для
использования этого режима требуется перезапись URL на стороне сервера, в основном вам нужно переписать все ваши ссылки на точку входа вашего приложения (например, index.html).

Причина этого заключается в том, что при первом посещении страницы ( /about), например, после обновления, браузер не может узнать, что это не настоящий URL, поэтому он загружается и загружается. Однако, если вы сначала загрузили корневую страницу и весь код javascript, то при переходе на /aboutAngular можно попасть туда, прежде чем браузер попытается подключиться к серверу и обработать его соответствующим образом.

Джеймс Шарп
источник
21
Когда это говорит «вы должны переписать все ваши ссылки на точку входа вашего приложения (например, index.html)», что это значит? Означает ли это, что я должен войти в свой $routeProviderи изменить пути каждого, templateUrlнапример, с templateUrl : '/views/about.html',на templateUrl : 'example.com/views/about.html',?
7
Нет, ваши правила в $ routeProvider должны оставаться такими, как они есть. Ответ относится к «серверной части». Это относится к изменению маршрутизации на сервере, который предоставляет ваши угловые html-страницы. Прежде чем каждый запрос попадает в ваше угловое приложение, он должен сначала пройти через серверную маршрутизацию, которая должна переписать все запросы, чтобы указывать на вашу угловую точку входа в приложение (например, «index.html» или «/», в зависимости от того, как ваш угловой маршруты работают).
Марни
В случае, если я подам свой минифицированный index.html через CDN, как будет работать этот механизм маршрутизации?
CrazyGeek
1
да - взгляните на stackoverflow.com/questions/22739455/…
Джеймс Шарп
5
Хорошая статья для apache, есть пример htaccess: ngmilk.rocks/2015/03/09/…
Alcalyn
63

Есть несколько вещей, которые нужно настроить, чтобы ваша ссылка в браузере была похожа, 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#how-to-configure-your-server -to-work-with-html5mode Также этот вопрос может помочь вам $ location / переключения между html5 и режимом hashbang / переписыванием ссылок

lokers
источник
Здравствуй. Я попробовал вышеуказанное решение, внес изменения в мой конфигурационный файл. Но все равно это не работает. Обновление URL по-прежнему дает ошибку «404 НЕ НАЙДЕНО».
2016 года
Как перенаправить / переписать в приложении, развернутом в Websphere?
Гэри
Я не понимаю, почему нет!
lokers
36

У меня была похожая проблема, и я решил ее:

  • Использование <base href="https://stackoverflow.com/index.html">на странице индекса

  • Используя промежуточное ПО перехвата всех маршрутов на моем узле / сервере Express следующим образом (поместите его после маршрутизатора):

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

Я думаю, что это должно заставить вас работать.

Если вы используете сервер Apache, вы можете захотеть изменить ваши ссылки mod_rewrite. Это не сложно сделать. Всего несколько изменений в конфигурационных файлах.

Все, что предполагает, что html5mode включен на angularjs. Сейчас. обратите внимание, что в угловых 1.2 объявление базового URL больше не рекомендуется на самом деле.

Тайе
источник
1
Это решение работало для меня с настройкой: <base href="https://stackoverflow.com/">и добавлением предложенной вами экспресс-маршрутизации. Большое спасибо.
Гилад Пелег
Тахир Чад, вам все еще нужно было использовать переписывание URL-адреса на сервере после реализации <base href="https://stackoverflow.com/index.html">?
Коди
Да, вы можете видеть переписывание URL как способ установить базовый URL вашего приложения / веб-сайта в камне (включая домен). HTML-оператор 'base url' - это просто способ убедиться, что все относительные ссылки правильно получены из одной и той же базы. Базовый URL не является абсолютно необходимым, если ваши ссылки являются абсолютными.
Тай
1
Когда я использую это, я просто вижу HTML-код на странице, а не отображается как фактическая страница.
Ной,
2
Этот ответ заслуживает тройной звезды! Спасибо за такой простой ответ. Все остальные просто повторяют одну и ту же строку о «необходимости перенаправить сервер».
Ахмед Хак
27

Решение для BrowserSync и Gulp.

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

Первая установка 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() ]
    }
  });
});
Оскар
источник
О, хватит! Наконец облегчение от разработки Angular View! И в качестве бонуса, стандартные URL-адреса (без хэш-бэнг) тоже маршрут! Спасибо!
бит
1
Работает как шарм ... Большое спасибо!
Нишант Наир
1
Если вы используете определенный порт (т. Е. Пустой шаблон Ionic работает на порте 8100), просто добавьте дополнительное свойство после сервера, т. Е. server: { ... }, port: 8100Затем просто добавьте serveзадачу в заданную по умолчанию задачу gulp (т.е. gulp.task('default', ['sass', 'serve']);), а затем вы можете запустить приложение без Cannot GET ...ошибок браузера при обновлении страницы при запуске gulp. Обратите внимание, что при запуске сервера с ionic serveошибками все еще встречается.
Люк Шоен
Это хорошо работает, когда я использую разработку browsersync, в prod я запускаю приложение как экспресс-приложение и перенаправляю весь маршрут в угловое приложение как app.get ('*', function (req, res) {req.session.valid = true ; res.redirect ('/');}); Страница не загружается, когда дают путь напрямую?
г-н AJ
13

Вам нужно настроить свой сервер так, чтобы все переписывалось в index.html для загрузки приложения:

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

грант
источник
1
Отлично, проблема для меня заключалась в том, чтобы использовать Laravel Forge для предоставления сервера, на котором try_files $uri $uri/ /index.php?...вместо нужной строки была указана соответствующая строка nginx index.html. Спасибо за ссылку!
CJ Томпсон
Должен быть лучший ответ, дает любую ситуацию, независимо от вашего сервера. Отлично работал с NodeJS
Джо Ллойд
10

Я написал простое промежуточное ПО для подключения, имитирующее переписывание 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)
            ];
          }
        }
      }
    }
  })
};
Мурат Чорлу
источник
Существует ли ручной способ перезаписи URL в $routeProvider?
1
Я получаю urlRewriteне определенное предупреждение при попытке запустить его, и мне трудно найти правильное соединение с перезаписью, которое я могу использовать.
Показывает мне ошибку «У построения объекта нет метода initConfig. Используйте --force для продолжения».
edonbajrami
8

Если вы находитесь в стеке .NET с MVC с AngularJS, это то, что вам нужно сделать, чтобы удалить '#' из URL:

  1. Настройте ваш базовый href на странице _Layout: <head> <base href="https://stackoverflow.com/"> </head>

  2. Затем добавьте следующее в конфигурацию вашего углового приложения: $locationProvider.html5Mode(true)

  3. Выше удалит «#» из 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" }
    );
Maksood
источник
8

Правило перезаписи 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

Джейсон
источник
Спасибо, правила IIS помогли мне с приложением angular2, развернутым в Azure, которое не направлялось на дочерний маршрут.
отпечаток
Я не могу отблагодарить вас за решение для IIS (localhost в VS 2013). Ударяя голову достаточно долго от разочарования, наконец нашел этот ответ. Работал как шарм.
Флорида Г.
5

Как уже упоминали другие, вам нужно переписать маршруты на сервере и установить <base href="https://stackoverflow.com/"/>.

Для 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()
    ];
  }
  ...
})
....
Brett
источник
4

Я использую apache (xampp) в своей среде разработки и apache на производстве, добавьте:

errorDocument 404 /index.html

.htaccess решить для меня эту проблему.

crlshn
источник
4

Для 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
                    }
                }
            }
        },
MrThunder
источник
над ответом есть 15, которые были поясом времени. 1. npm install connect-modrewrite --save2. require in gruntfile3. скопируйте вышеуказанный серверный объект
Omar
Спасибо, это сработало для меня в gulp 4 с настройкой browserSync.
Абдеали Чанданвала
Рад, что это помогло @Abdeali Chandanwala!
MrThunder
@ Омар, я не согласен с вами, менее продвинутым пользователям, таким как я, полезно узнать, как добавить их в gulpfile. Лучше всего помнить, что у людей разные уровни знаний, и не нужно было бы просто писать требовать в gruntfile, так как я предполагаю, что они понимают, как добавить его в gulp.
MrThunder
3

Я решил

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

Я отвечаю на этот вопрос из более крупного вопроса:

Когда я добавляю $ 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'));
Ironheartbj18
источник
Спасибо, это решение. Для Nodejs добавьте app.js в app.use ('/ *', index);
Тигин
2

Я считаю, что ваша проблема в отношении сервера. В англоязычной документации по режиму HTML5 (по ссылке в вашем вопросе) говорится:

На стороне сервера Для использования этого режима требуется перезапись URL на стороне сервера, в основном вам нужно переписать все ваши ссылки на точку входа вашего приложения (например, index.html)

Я считаю, что вам нужно настроить переписать URL-адрес с / о /.

Lucuma
источник
Спасибо за ваш ответ. Поэтому, когда я нахожусь на странице about и я обновляюсь, сервер должен переписать URL в /? Проблема в том, что я работаю с бэкэндом Rails, который находится в другом домене. Все общение происходит через вызовы API. Как бы я переписал эти URL?
Дитер де Месмакер
Дело в том, что ваше приложение доступно по маршруту вашего сервера / поэтому, когда вы обновляете URL-адрес, который / о браузере будет запрашивать с вашего сервера любую страницу в / о (в этом случае у вас нет страниц, поэтому вам нужно перенаправить те вернулись).
lucuma
2

У нас был сервер перенаправления в Express:

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

и у нас все еще возникали проблемы с обновлением страницы, даже после того, как мы добавили <base href="https://stackoverflow.com/" />.

Решение: убедитесь, что вы используете реальные ссылки на своей странице для навигации; не вводите маршрут в URL, иначе вы получите обновление страницы. (глупая ошибка, я знаю)

:-П

Cody
источник
но в связи с этим каждый HTTP запрос будет иметь индексный файл, например , как: getJsonFromServer / - запрос HTTP , который возвращает данные , но из - за этой конфигурации он также будет возвращать индекс страницы
Виджай
1

Наконец, у меня появился способ решить эту проблему на стороне сервера, так как это больше похоже на проблему с самими AngularJ, я использую 1.5 Angularjs и у меня возникла такая же проблема при перезагрузке страницы. Но после добавления приведенного ниже кода в мой server.jsфайл это спасает мой день, но это не является правильным решением или не хорошим способом.

app.use(function(req, res, next){
  var d = res.status(404);
     if(d){
        res.sendfile('index.html');
     }
});
Анил Ядав
источник
0

Я нашел даже лучший плагин 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)
          ];
        }
      },
    }
},
Михал Лах
источник
Модуль grunt-connect-pushstate устарел
Эван Плейс
0
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
        });
    }
keiwt
источник
0

У меня была такая же проблема с приложением 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);
}

Надеюсь, это будет полезно для кого-то.

Игорь Збойчик
источник
0

Gulp + browserSync:

Установите connect-history-api-fallback через npm, позже настройте задачу подачи сообщений

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

gulp.task('serve', function() {
  browserSync.init({
    proxy: {
            target: 'localhost:' + port,
            middleware: [ historyApiFallback() ]
        }
  });
});
Оскар Кайседо
источник
0

Ваш код на стороне сервера - JAVA, затем выполните следующие шаги

Шаг 1: Загрузите JAR urlrewritefilter. Нажмите здесь и сохраните, чтобы построить путь. WEB-INF / lib

шаг 2: включить режим HTML5 $ locationProvider.html5Mode (true);

шаг 3: установить базовый URL <base href="https://stackoverflow.com/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>
сентил раджа
источник
Как добавить правило для динамического URL, как - test.com/user/101 test.com/user/102
Кришна Кумар Chourasiya
0

У меня есть это простое решение, которое я использую, и оно работает.

В приложении / 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);
}
Эмека Мбах
источник
0

Я решил проблему, добавив приведенный ниже фрагмент кода в файл node.js.

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

Примечание: когда мы обновляем страницу, она будет искать API вместо страницы Angular (из-за отсутствия тега # в URL). Используя приведенный выше код, я перенаправляю на URL с #

Рам Голлапалли
источник
-2

Просто напишите правило в 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('!');
}
user3084147
источник