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

169

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

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

Теги:
angular-routing

25 ответов

90
Лучший ответ

Из angular docs

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

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

  • 21
    Когда это говорит «вы должны переписать все ваши ссылки на точку входа вашего приложения (например, index.html)», что это значит? Означает ли это, что я должен зайти в свой $routeProvider и изменить пути каждого templateUrl например, с templateUrl : '/views/about.html', на templateUrl : 'example.com/views/about.html', templateUrl : '/views/about.html',
  • 7
    Нет, ваши правила в $ routeProvider должны оставаться такими, как они есть. Ответ относится к «серверной части». Это относится к изменению маршрутизации на сервере, который предоставляет ваши угловые html-страницы. Прежде чем каждый запрос попадает в ваше угловое приложение, он должен сначала пройти через серверную маршрутизацию, которая должна переписать все запросы, чтобы указывать на вашу угловую точку входа в приложение (например, «index.html» или «/», в зависимости от того, как ваш угловой маршруты работают).
Показать ещё 8 комментариев
56

Есть несколько вещей, которые нужно настроить, чтобы ваша ссылка в браузере выглядела как 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

  • 0
    Привет. Я попробовал вышеуказанное решение, внес изменения в мой конфигурационный файл. Но все равно это не работает. Обновление URL по-прежнему дает ошибку «404 НЕ НАЙДЕНО».
  • 0
    Как перенаправить / переписать в приложении, развернутом в Websphere?
Показать ещё 2 комментария
30

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

  • Используя <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 больше не рекомендуется.

  • 0
    Это решение работало для меня с настройкой: <base href="/"> и добавлением предложенной вами экспресс-маршрутизации. Большое спасибо.
  • 0
    Тахир Чад, вам все еще нужно было использовать переписывание URL-адреса на сервере после реализации <base href="/index.html"> ?
Показать ещё 7 комментариев
25

Решение для 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() ]
    }
  });
});
  • 0
    О, хватит! Наконец облегчение от разработки Angular View! И в качестве бонуса, стандартные URL-адреса (без хэш-бэнг) тоже маршрут! Спасибо!
  • 1
    Работает как шарм ... Большое спасибо!
Показать ещё 2 комментария
11

Вам нужно настроить сервер для перезаписи всего на 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 как try_files $uri $uri/ /index.php?... вместо необходимого index.html . Спасибо за ссылку!
  • 0
    Должен быть лучший ответ, дает любую ситуацию, независимо от вашего сервера. Отлично работал с NodeJS
9

Я написал простую связующую среду для моделирования 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)
            ];
          }
        }
      }
    }
  })
};
  • 0
    Есть ли ручной способ перезаписи URL в $routeProvider ?
  • 1
    Я получаю urlRewrite не определено при попытке запустить его, и мне трудно найти правильное соединение с перезаписью, которое я могу использовать.
Показать ещё 1 комментарий
7

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

  • 0
    Спасибо, правила IIS помогли мне с приложением angular2, развернутым в Azure, которое не направлялось на дочерний маршрут.
  • 0
    Я не могу отблагодарить вас за решение для IIS (localhost в VS 2013). Ударяя голову достаточно долго в отчаянии, наконец нашел этот ответ. Работал как шарм.
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" }
    );
4

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

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

errorDocument 404 /index.html

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

2

Для 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
                    }
                }
            }
        },
  • 0
    есть 15 выше этого ответа, которые были поясом времени. 1. npm install connect-modrewrite --save 2. require in gruntfile 3. скопируйте указанный выше серверный объект
2

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

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

Я решил

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

Если вы работаете локально, вы можете использовать: connect-modrewrite

См. этот учебник: http://ericduran.io/2013/05/31/angular-html5Mode-with-yeoman/

1

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

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

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

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

: - P

  • 0
    но из-за этого КАЖДЫЙ запрос http будет иметь индексный файл, например, например: / getJsonFromServer - запрос http, который возвращает данные, но благодаря этой конфигурации он также вернет страницу индекса
1

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

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

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

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

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

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

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

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

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

Код вашей серверной части - 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>
  • 0
    Как добавить правило для динамического URL, например - test.com/user/101 test.com/user/102
0

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

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

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

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

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

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

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

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

0

Я нашел еще лучший плагин 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)
          ];
        }
      },
    }
},
  • 0
    Модуль grunt-connect-pushstate устарел

Ещё вопросы

Сообщество Overcoder
Наверх
Меню