Angular生产环境页面刷新避免404的正确实现方案
问题描述
本地开发环境中,调用window.location.reload()能正常实现页面刷新,但将Angular应用发布到生产环境后,执行该代码会出现404错误。尝试过window.location.href= '/portal/students/view-student', data.id;、window.location.href = window.location.protocol + "//" + window.location.host + '/portal/students/view-student', data.id;以及location.replace()等方法,均未解决问题。
提交方法代码
public onSubmit($event: MouseEvent) { //($event.target as HTMLButtonElement).disabled = true; this.submitted = true; console.log(this.form.value); if (this.form.invalid) {return;} const payload = this.form.value; payload.id = this.student.id; payload.centerId = this.student.centerId; this.studentService.postUrl(`${payload.id}/update-student`,payload) .subscribe((data) => { this.initForms(); Swal.fire('Student Information Updated', 'Student information has been updated.', 'success'); this.router.navigate(['/portal/students/view-student', data.id]); window.location.reload(); }); }
发布后的Index文件
<!DOCTYPE html><html class="loading" lang="en" data-textdirection="ltr"><head><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin=""> <base href="/StudentsApp/"> <title>Students App</title> <link href="https://unpkg.com/font-awesome@4.7.0/css/font-awesome.css" rel="stylesheet"> <link href="StudentsApp/assets/fonts/feather/style.min.css" rel="stylesheet" media="print" onload="this.media='all'"><noscript> <link rel="stylesheet" href="StudentsApp/assets/fonts/feather/style.min.css"></noscript> <link href="StudentsApp/assets/fonts/line-awesome/css/line-awesome.min.css" rel="stylesheet" media="print" onload="this.media='all'"> <noscript><link rel="stylesheet" href="StudentsApp/assets/fonts/line-awesome/css/line-awesome.min.css"></noscript> <link href="StudentsApp/assets/fonts/flag-icon-css/css/flag-icon.min.css" rel="stylesheet" media="print" onload="this.media='all'"> <noscript><link rel="stylesheet" href="StudentsApp/assets/fonts/flag-icon-css/css/flag-icon.min.css"></noscript> <link href="StudentsApp/assets/fonts/simple-line-icons/style.min.css" rel="stylesheet" media="print" onload="this.media='all'"><noscript> <link rel="stylesheet" href="StudentsApp/assets/fonts/simple-line-icons/style.min.css"></noscript> <link href="StudentsApp/assets/fonts/meteocons/style.css" rel="stylesheet" media="print" onload="this.media='all'"><noscript> <link rel="stylesheet" href="StudentsApp/assets/fonts/meteocons/style.css"></noscript> <link rel="apple-touch-icon" href="StudentsApp/assets/images/ico/apple-icon-120.png"> <link rel="apple-touch-icon" sizes="152x152" href="StudentsApp/assets/images/ico/apple-icon-152.png"> <link rel="apple-touch-icon" sizes="76x76" href="StudentsApp/assets/images/ico/apple-icon-76.png"> <link rel="apple-touch-icon" sizes="60x60" href="StudentsApp/assets/images/ico/apple-icon-60.png"> <link rel="shortcut icon" type="image/x-icon" href="StudentsApp/assets/images/ico/favicon.ico"> <body class="vertical-layout 1-column blank-page pace-done menu-collapsed menu-hide vertical-overlay-menu" data-open="click" data-menu="vertical-menu-modern" data-col="2-columns"> <app-main></app-main> <script src="runtime.91d60757ad11e8be.js" type="module"></script><script src="polyfills.e05052d830462261.js" type="module"></script><script src="scripts.f9627fecd7dd714a.js" defer></script><script src="main.4db38e61597a34f8.js" type="module"></script> </body></html>
解决方案
1. 移除冗余的刷新逻辑
你当前代码中先调用this.router.navigate完成前端路由跳转,紧接着执行window.location.reload()完全没必要。前端路由跳转已经能加载目标页面,刷新操作会触发浏览器直接向服务器请求当前路由路径,而服务器没有对应文件,导致404。直接删除window.location.reload()即可。
如果需要确保页面显示最新数据,在目标组件(view-student)的ngOnInit生命周期钩子中重新调用接口获取数据即可,比如:
ngOnInit(): void { this.studentService.getStudent(this.studentId).subscribe(data => { // 更新组件数据 this.student = data; }); }
2. 配置服务器重定向规则(核心解决方法)
Angular是单页应用,所有路由都由前端处理。生产环境刷新页面时,浏览器会直接请求当前URL对应的资源,但服务器上只有index.html这一个入口文件,因此需要配置服务器将所有路由请求重定向到/StudentsApp/index.html,由Angular接管路由处理。
不同服务器的配置方式如下:
- Apache:在项目根目录创建
.htaccess文件,添加以下规则RewriteEngine On RewriteBase /StudentsApp/ RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /StudentsApp/index.html [L] - Nginx:在服务器配置的
server块中添加location /StudentsApp/ { try_files $uri $uri/ /StudentsApp/index.html; } - IIS:创建
web.config文件,添加重写规则<configuration> <system.webServer> <rewrite> <rules> <rule name="Angular Routes" 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="/StudentsApp/index.html" /> </rule> </rules> </rewrite> </system.webServer> </configuration>
3. 若必须强制刷新页面的正确写法
如果确实需要强制刷新整个页面(不推荐,会影响用户体验),要基于base href构造完整的URL:
const fullUrl = `${window.location.origin}/StudentsApp/portal/students/view-student/${data.id}`; window.location.href = fullUrl;
内容的提问来源于stack exchange,提问作者Zidane

