AngularJS 如何用 $location 开启 HTML5 mode 并配置 base 标签与服务器端 URL 回退
AngularJS 如何用 $location 开启 HTML5 mode 并配置 base 标签与服务器端 URL 回退【免费下载链接】angular.jsAngularJS - HTML enhanced for web apps!项目地址: https://gitcode.com/gh_mirrors/an/angular.js如果你的 AngularJS 应用地址栏里还是http://example.com/#!/foo这样的 hashbang URL这篇文档给出官方的完整操作路径通过$locationProvider开启 HTML5 mode在页面 head 中配置base标签并让服务器把所有应用路由回退到入口文件。完成后现代浏览器的地址栏会使用常规 URL如http://example.com/foo不再依赖#片段。前提是你的应用可以控制托管它的 Web 服务器HTML5 mode 要求服务器端配置这一点在官方模式对比表中被明确列出。一、开启 HTML5 mode修改 $locationProvider 配置在应用的 config 块中获取$locationProvider并调用html5Mode。官方文档给出的默认配置对象为{ enabled: false, requireBase: true, rewriteLinks: true }开启 HTML5 mode 的最短写法angular.module(app, []) .config(function($locationProvider) { $locationProvider.html5Mode(true).hashPrefix(!); });html5Mode(true)等价于{enabled: true}默认值是false即 Hashbang mode。hashPrefix默认是!它只在 Hashbang mode 或 HTML5 mode 下不支持 History API 的旧浏览器中生效所以即使开启 HTML5 mode 也建议保留。需要更细的控制时传对象形式官方支持两个仅影响 HTML5 mode 的字段{enabled: true, requireBase: false}不强制要求base标签详见第三节有副作用{enabled: true, rewriteLinks: false}关闭链接改写所有链接点击都会触发完整页面刷新rewriteLinks还可以传一个字符串此时只有带该属性名的a元素会被改写例如设为internal-link后a href/some/path internal-link会被改写而a href/some/path会整页刷新。注意此处不做属性名规范化internalLink不会匹配internal-link。不设置html5Mode时应用处于 Hashbang mode所有浏览器都用 hashbang URLAngularJS 也不拦截、不改写链接hash 之外的 URL 部分变化会导致整页刷新。二、在 head 中配置base标签开启 HTML5 mode 后base标签是硬性要求默认requireBase: true。它的作用是让应用内所有相对 URL 都基于这个 base 解析无论用户从哪个入口进来同时让 AngularJS 能区分 URL 中哪些是应用 base、哪些应交给应用处理。按部署位置设置 base 的值来自官方错误文档$location:nobase部署在根上下文如https://myapp.com/head base href/ ... /head部署在子上下文如https://myapp.com/subapp/head base href/subapp/ ... /head如果 base 设置不对或缺失$location服务无法正常工作缺少 base 标签且未关闭requireBase时会直接报错$location in HTML5 mode requires a base tag to be present!错误码$location:nobase。可选分支——不用base标签传对象关闭要求$locationProvider.html5Mode({ enabled: true, requireBase: false });官方明确警告在 IE9 中用$location解析相对路径时会产生不良副作用且如果还需要兼容没有history.pushState的浏览器不指定 base URL 时$location的 hashbang 回退机制无法正常工作。因此除非你明确放弃这些场景建议始终保留base标签。在子上下文中部署时还有一个细节AngularJS 1.3 之前没有 base 的强制要求容易出现部署在根上下文正常、移到子上下文就坏的问题原因是子上下文里的绝对 URL 会解析到根上下文。官方给出的对策是全应用使用相对 URL!-- wrong: -- a href/userProfileUser Profile/a !-- correct: -- a hrefuserProfileUser Profile/a三、服务器端 URL 回退HTML5 mode 下 URL 不再带 hash用户直接打开或刷新http://example.com/foo时服务器并不会知道/foo对应哪个静态文件。官方文档的要求是服务器端必须做 URL 重写把所有链接重写到你应用的入口文件例如index.html。官方组件路由器教程补充说明了这一点使用 HTML5 mode 时托管应用的 Web 服务器必须理解对代表应用路由的 URL 请求都应响应 index.html开发环境下他们使用lite-server来完成这个工作。也就是说这一层配置由你的 Web 服务器负责仓库文档没有给出特定服务器的配置片段只给出了行为要求任何命中应用路由的请求都回落到入口文件其余静态资源照常分发。四、结果验证文档用两组测试示例结果来自官方文档展示了 HTML5 mode 生效后$location的行为。以base href/级别的应用为例it(should show example, function() { module(function($locationProvider) { $locationProvider.html5Mode(true); $locationProvider.hashPrefix(!); }); inject(function($location) { // in browser with HTML5 history support: // open http://example.com/#!/a - rewrite to http://example.com/a // (replacing the http://example.com/#!/a history record) expect($location.path()).toBe(/a); $location.path(/foo); expect($location.absUrl()).toBe(http://example.com/foo); expect($location.search()).toEqual({}); $location.search({a: b, c: true}); expect($location.absUrl()).toBe(http://example.com/foo?abc); $location.path(/new).search(xy); expect($location.url()).toBe(/new?xy); expect($location.absUrl()).toBe(http://example.com/new?xy); }); });对照上面这段文档示例你在真实应用里可以核对的行为是打开一个 hashbang URLhttp://example.com/#!/a后现代浏览器会把它重写为常规 URLhttp://example.com/a并替换原来的历史记录条目反向地旧浏览器打开常规 URL 会被重定向到 hashbang URL。注意这个转换只发生在解析初始 URL即页面加载/刷新时在地址栏手动输入 hashbang 或常规 URL 不会触发转换。调用$location.path(/foo)后地址栏变为/foo形式设置 search 后变为/foo?abc。页面中的普通链接如a href/some?foobar在 HTML5 mode 下被 AngularJS 拦截点击只更新 URL、不做整页刷新旧浏览器中点击后 URL 变为/index.html#!/some?foobar。以下三类链接不会被改写浏览器会按原链接整页刷新这是预期行为而非故障带target属性的链接如a href/ext/link?ab target_selflink/a指向其他域名的绝对链接如a hrefhttp://angularjs.org/link/a以/开头但指向不同 base path 的链接如a href/not-my-base/linklink/a。另有一个例外只包含 hash 片段的链接a href#target只会修改$location.hash()不改变其余 URL可用于同页锚点滚动。五、已知限制与排查点base href 的边界当前 URL 落在 base href 之外时$location无法正常工作。以base href/base/为例URL/base无尾斜杠实际上指向根目录下的base文件在应用之外。如果希望用户能通过/base这样的 URL 访问应用需要让服务器把这类请求重定向到/base/。测试中操作 $location在 AngularJS 的 scope 生命周期之外改$location如测试或 DOM 事件回调中必须手动调用$apply传播变更it(should..., inject(function($location, $rootScope, serviceUnderTest) { $location.path(/new/path); $rootScope.$apply(); // test whatever the service should do... }));path 的前缀$location.path()设置的路径必须以/开头缺少前导斜杠时 setter 会自动补上Hashbang mode 中的!前缀不属于$location.path()它实际是hashPrefix。$location 不做整页刷新它只改 URL。需要改 URL 并刷新页面时用更底层的$window.location.href。$location.state 的适用条件$location.state方法只在 HTML5 mode 且浏览器支持 HTML5 History API 时可用例如 IE9、Android 2.3 上不可用否则抛出History API state support is available only in HTML5 mode and only in browsers supporting HTML5 History API错误码$location:nostate。参考资料完整指南Using $locationbase 标签错误说明$location:nobase、$location:nostateHTML5 mode 结合组件路由器的实际项目示例Component Router guide【免费下载链接】angular.jsAngularJS - HTML enhanced for web apps!项目地址: https://gitcode.com/gh_mirrors/an/angular.js创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考