Перезагрузка страницы дает неправильный запрос 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-ref, чтобы исключить /#/.

Проблема

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

Спасибо заранее.

Ответ 1

Из angular docs

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

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

Ответ 2

Есть несколько вещей, которые нужно настроить, чтобы ваша ссылка в браузере выглядела как http://yourdomain.com/path, и это ваша сторона angular config + server

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/link rewriting

Ответ 3

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

  • Используя <base href="/index.html"> на индексной странице

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

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

Я думаю, что это должно помочь вам.

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

Все, что предполагает, что html5mode включен в angularjs. Теперь. обратите внимание, что в angular 1.2 объявление базового url больше не рекомендуется.

Ответ 4

Решение для 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() ]
    }
  });
});

Ответ 6

Я написал простую связующую среду для моделирования url-rewriting в проектах 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)
            ];
          }
        }
      }
    }
  })
};

Ответ 7

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

  • Настройте свой базовый href на странице _Layout: <head> <base href="/"> </head>

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

  • Выше будет удалять '#' из URL-адреса, но обновление страницы не будет работать, например. если вы находитесь на странице "yoursite.com/about", обновление будет дано вам 404. Это связано с тем, что MVC не знает о маршрутизации angular, а по шаблону MVC он будет искать страницу MVC для "about", которая не существует в пути маршрутизации MVC. Обходным путем для этого является отправка всех запросов страницы MVC в одно представление MVC, и вы можете сделать это, добавив маршрут, который ловит все URL


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

Ответ 8

Правила перезаписи URL-адреса IIS для предотвращения ошибки 404 после обновления страницы в html5mode

Для angular работает под 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

Для angular работает под 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

Ответ 9

Как уже упоминалось, вам нужно переписать маршруты на сервере и установить <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()
    ];
  }
  ...
})
....

Ответ 10

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

errorDocument 404 /index.html

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

Ответ 11

Я решил

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')
                  ];
              }
        }
      },

Ответ 12

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

Когда я добавляю $locationProvider.html5Mode (true), мой сайт не позволит вставлять URL-адреса. Как настроить мой сервер для работы, когда html5Mode является истинным?

Когда у вас включен 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'));

Ответ 13

Для 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
                    }
                }
            }
        },

Ответ 14

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

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

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

Ответ 15

Мы перенаправили сервер в Express:

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

и мы все еще получали проблемы с обновлением страницы, даже после добавления <base href="/" />.

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

: - P

Ответ 17

Я нашел еще лучший плагин Grunt, который работает, если у вас есть index.html и Gruntfile.js в том же каталоге;

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

После этого в вашем файле Grunt:

 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)
          ];
        }
      },
    }
},

Ответ 18

У меня была такая же проблема, прежде чем при обновлении страниц браузер отправил значение своего адресного знака на сервер, что, очевидно, потерпит неудачу (с тех пор как это переписанный адрес).

Вы также должны заполнить логику reqwritting URL-адресов на стороне сервера. См. Ссылку ниже, это лучший пример, который я нашел о том, как это сделать, и это отлично работает для меня:

https://github.com/bdunklau/LittleBlueBird/wiki/URL-Rewriting-and-HTML5-in-AngularJS

В основном вам просто нужно перенаправить все запросы в контейнер содержимого главной страницы (в большинстве случаев - index.html).

Ответ 19

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
        });
    }

Ответ 20

У меня была та же проблема с приложением java + angular, сгенерированным с помощью JHipster. Я решил его с помощью фильтра и списка всех страниц angular в свойствах:

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);
}

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

Ответ 21

Gulp + browserSync:

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

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

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

Ответ 22

Код вашей серверной части - JAVA, затем выполните следующие шаги.

Шаг 1: Загрузите urlrewritefilter JAR Нажмите здесь и сохранить для построения пути 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>

Ответ 23

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

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

Ответ 24

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

В приложении/Исключения/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);
}

Ответ 25

Просто напишите правило в 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="/">