Django+Angular动态页面刷新后返回API响应而非Angular页面问题
Angular是单页应用(SPA),首次加载时浏览器请求根路径获取index.html,之后所有路由切换由前端Angular Router处理。但刷新页面时,浏览器会直接向服务器请求当前URL,此时Django的路由匹配到了product/home/<str:handle>/<int:id>,直接返回API的JSON响应,而非Angular的index.html,导致Angular无法初始化渲染页面。
核心思路是让Django仅处理API请求,所有前端路由路径都返回Angular的index.html,由Angular Router接管后续路由解析。
1. 重构Django路由,分离API与前端路径
修改urls.py,给所有API路由添加统一前缀(比如/api/),并添加通配符路由匹配所有前端路径,返回Angular的index.html:
# urls.py from django.urls import path, re_path from django.shortcuts import render from .views import ProductGet # API路由(统一前缀/api/) urlpatterns = [ path('api/product/home/<str:handle>/<int:id>', ProductGet), ] # 所有非API路径返回Angular的index.html def serve_angular(request): # 若Angular打包后的index.html放在Django templates目录下,直接使用render # 若打包文件在自定义路径,可读取文件返回: # with open(os.path.join(settings.BASE_DIR, 'dist/your-angular-app/index.html'), 'r') as f: # return HttpResponse(f.read()) return render(request, 'index.html') urlpatterns += [ path('', serve_angular), re_path(r'^.*$', serve_angular), # 匹配所有其他路径 ]
2. 调整Angular的API请求路径
由于Django API路由添加了/api/前缀,修改productService中的getProduct方法,更新请求URL:
// product.service.ts getProduct(id: number, title: string) { return this.http.get(`/api/product/home/${title}/${id}`); }
3. 启用Angular HTML5路由模式
确保Angular使用HTML5模式(而非哈希模式),并配置正确的base href:
修改app-routing.module.ts
import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { ProductComponent } from './product/product.component'; const routes: Routes = [ // 你的路由配置示例 { path: 'product/home/:title/:id', component: ProductComponent }, ]; @NgModule({ imports: [RouterModule.forRoot(routes, { useHash: false })], // 启用HTML5模式 exports: [RouterModule] }) export class AppRoutingModule { }
修改index.html
在<head>标签内添加base href:
<base href="/">
4. 配置Django静态文件(Angular打包资源)
将Angular打包后的静态文件(dist目录下的js、css、assets等)复制到Django的static目录下,并在settings.py中配置静态文件路径:
# settings.py import os STATIC_URL = '/static/' STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'static'), ]
刷新页面时,浏览器请求的URL会被Django的通配符路由捕获,返回Angular的index.html。Angular加载后,由前端Router解析URL中的参数(productName和productId),再通过调整后的API路径向Django请求数据,最终渲染出正确的产品页面。
内容的提问来源于stack exchange,提问作者Akzhol

