Chrome开启预加载后Angular2组件ngOnInit中HTTP请求pending问题
嘿,我之前也碰到过几乎一模一样的问题!结合你的环境配置和症状来看,这绝对是Chrome的预测服务在搞鬼,和你的API请求产生了冲突。下面给你拆解一下原因,还有几个亲测有效的解决办法:
环境版本
@angular/cli: 1.2.0- PHP 7.0.8
- Zend Expressive 2
- Apache 2.4.23
- Chrome 65.0.3325.181
- Windows 7
问题描述
我有一个Angular 2应用,后端用PHP(基于Zend Expressive 2)作为API处理所有XHR请求,平时运行都正常;但当Chrome启用**「使用预测服务加快页面加载速度」**选项后,重新加载应用时,组件ngOnInit内发送的HTTP请求会长时间处于pending状态,要么自行恢复处理,要么就一直卡着直到超时。
问题原因分析
Chrome的这个预测服务会在页面加载前,提前预取它认为可能需要的资源(包括你的API接口),这就导致了两个核心问题:
- 连接资源被占用:Apache的并发连接数是有限的,预取请求先占了坑,当Angular实际发起业务请求时,没有可用连接,只能进入pending状态等待。
- 会话锁冲突:PHP默认用文件存储会话,并且会给会话文件加锁,预取请求如果占用了会话锁,后续Angular发起的请求就只能等着锁释放,自然就pending了。
可行的解决方案
1. 直接阻止Chrome预取API接口
在你的PHP API响应里添加特定头,明确告诉浏览器不要预取这些接口,这是最直接的办法:
// 在Zend Expressive的控制器或中间件中添加响应头 $response = $response->withHeader('X-Robots-Tag', 'noindex,nofollow'); // 或者用Link头的方式,效果一样 $response = $response->withHeader('Link', '<' . $request->getUri() . '>; rel="nofollow"');
这样Chrome的预测服务就不会提前碰你的API接口了。
2. 优化后端服务器配置
- Apache调整:修改
httpd.conf,调大并发连接相关参数,避免闲置连接占资源:
MaxKeepAliveRequests 1000 # 增加每个连接可处理的请求数 KeepAliveTimeout 5 # 缩短闲置连接的超时时间
- PHP-FPM调整:如果用的是PHP-FPM,修改
php-fpm.conf,确保有足够的进程处理请求:
pm.max_children = 20 # 根据服务器内存调整,比如2核2G服务器设20足够 pm.start_servers = 5 pm.min_spare_servers = 5 pm.max_spare_servers = 10
3. Angular端请求优化
在ngOnInit的HTTP请求里添加禁用缓存的头,避免浏览器把预取的缓存和实际请求搞混:
import { HttpHeaders } from '@angular/http'; // Angular 2用HttpModule的话用这个 // 构造请求头 const headers = new HttpHeaders() .set('Cache-Control', 'no-cache, no-store, must-revalidate') .set('Pragma', 'no-cache') .set('Expires', '0'); // 发起请求时带上头 this.http.get('/api/your-business-endpoint', { headers: headers }) .subscribe(data => { // 处理响应 }, error => { // 处理错误 });
另外,也可以考虑把请求从ngOnInit移到ngAfterViewInit,不过这只是延迟请求发起时间,属于临时缓解,不如前面的方法彻底。
4. 临时验证方案(仅测试用)
如果只是想快速验证问题是否确实来自Chrome的预测服务,可以让用户关闭这个选项:打开Chrome设置 → 隐私和安全 → 预加载网页以加快浏览和搜索速度,把开关关掉。但这只是临时方案,不能要求所有用户都这么做,所以还是优先前面的解决办法。
内容的提问来源于stack exchange,提问作者Ashish Ranjan
相关产品推荐
相关产品推荐

