Angular ngOnInit中GET请求触发两次的问题排查
Angular ngOnInit发起请求导致后端收到两次请求的原因分析
问题现象
在Angular组件的ngOnInit钩子中发起带Token的GET请求时,Node+Express后端会收到两次请求:
- 首次请求:无Token,请求头的
user-agent为node - 第二次请求:携带正确Token,请求头为浏览器标识
使用Postman发起请求则无此问题,仅收到一次带Token的请求。
Angular端代码
服务层请求代码
public async getAllIngredients(): Promise<Ingredient[]> { try { return await firstValueFrom( this.http.get<Ingredient[]>( `${environment.API_URL}/your-chef/ingredients/getIngredients`, { withCredentials: true, } ) ); } catch (error) { throw error; } }
组件初始化代码
@Component({ selector: 'ingredients-page', imports: [SearchInputComponent, TranslateModule, IngredientCardComponent], templateUrl: './ingredients-page.component.html', styleUrl: './ingredients-page.component.scss', }) export class IngredientsPageComponent implements OnInit { public ingredients: Ingredient[] = []; constructor(private ingredientService: IngredientService) {} public async ngOnInit(): Promise<void> { try { console.log('entering the function'); this.ingredients = await this.ingredientService.getAllIngredients(); } catch (error) { console.log('function error'); throw error; } } }
Node+Express后端代码
Token验证中间件
const isAuthenticated = ( req: Request, res: Response, next: NextFunction ): void => { try { req.session = {}; // 排除无需验证的登录/注册路由 const excludedRoutes: string[] = ["/user/login", "/user/register"]; if (excludedRoutes.includes(req.path)) { return next(); } console.log(req.method); // 跳过checkToken路由的验证(登录时已设置会话) if (req.path !== "/user/checkToken") { const data: JwtPayload | string = verifyToken(req.cookies.access_token); req.session.user = data as IUserSession; } next(); } catch (error: any) { if (error.code === ERRORS.USER.INVALID_TOKEN.code) { res.status(error.status).send({ message: error.message }); } else { res.status(500).send({ message: "Error when validate authentication" }); } } };
CORS与中间件配置
app.use( cors({ origin: process.env.FRONT_END_HOST, credentials: true, }) ); app.use(isAuthenticated);
两次请求头对比
首次请求(无Token)
{ "host": "localhost:3000", "connection": "keep-alive", "accept": "application/json, text/plain, */*", "accept-language": "*", "sec-fetch-mode": "cors", "user-agent": "node", "accept-encoding": "gzip, deflate" }
第二次请求(带Token)
{ "host": "localhost:3000", "connection": "keep-alive", "sec-ch-ua-platform": "\"Windows\"", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36", "accept": "application/json, text/plain, */*", "sec-ch-ua": "\"Chromium\";v=\"134\", \"Not:A-Brand\";v=\"24\", \"Google Chrome\";v=\"134\"", "sec-ch-ua-mobile": "?0", "origin": "http://localhost:4200", "sec-fetch-site": "same-site", "sec-fetch-mode": "cors", "sec-fetch-dest": "empty", "referer": "http://localhost:4200/", "accept-encoding": "gzip, deflate, br, zstd", "accept-language": "es,es-ES;q=0.9,ca;q=0.8,en;q=0.7", "cookie": "access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2Nzc1N2YwZGZlYzMxZDgzMWE3OWQ2ZGQiLCJpYXQiOjE3NDE5NTIwMzAsImV4cCI6MTc0MTk1OTIzMH0.hrOWu0WwxX2d7zNqnv1XPeGKw9tAz6FHgcV1gIpQJ3Q", "if-none-match": "W/\"128-RGyy7TUC0nG6pCSxdFRvDFMWJbo\"" }
排查情况
- 仅Angular开发服务器控制台可见重复请求,浏览器控制台无异常,且
ngOnInit内的日志仅打印一次 - 将请求改为按钮触发(用户交互触发)时,无重复请求
- 调整CORS配置无法解决问题
原因分析
核心原因是你的Angular应用启用了服务器端渲染(SSR):
- 在开发环境中,SSR会先在服务器端(Node进程)渲染组件,此时
ngOnInit会在服务器端执行,发起一次请求——由于是Node进程发起,没有浏览器的Cookie环境,所以请求不带Token,user-agent为node。 - 服务器端渲染完成后,页面发送到浏览器,客户端进行**水合(Hydration)**时,组件的
ngOnInit会再次执行,发起第二次请求——此时是浏览器环境,携带了Cookie中的Token,请求头为浏览器标识。
而按钮触发的请求属于用户交互,仅在客户端执行,不会触发服务器端的渲染请求,因此不会出现重复请求的情况。
内容的提问来源于stack exchange,提问作者Gerard
相关产品推荐
相关产品推荐

