You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AngularJS应用中如何让控制器内的HTTP请求仅执行一次

解决AngularJS控制器中HTTP请求仅执行一次的问题

你的代码之所以没生效,核心原因是控制器每次初始化时,局部变量contadorInicioCtr都会被重新声明并重置为0——也就是说,每次进入这个视图,控制器都会从头执行,contadorInicioCtr永远会变成1,自然每次都会触发请求。

下面是几种可靠的解决思路,你可以根据自己的场景选择:

方案1:利用$rootScope存储全局标记(简单快速)

$rootScope是AngularJS的全局作用域,只要应用不刷新,存储的状态就会保留。我们可以在里面加一个标记,用来判断请求是否已经执行过:

aldro_app.controller('ctrInicio', function ($scope, $http, $rootScope) {
    // 初始化全局标记(如果还没设置的话)
    if (!$rootScope.hasFetchedBills) {
        $rootScope.hasFetchedBills = false;
    }

    if (!$rootScope.hasFetchedBills) {
        var id = parseInt(getVariable("idcontrato"));
        var url = "http://api/url";
        
        $http({
            url: url,
            method: 'POST', // 记得补全请求方法
            data: { id: id } // 根据API需求传递参数
        }).then(function(response) {
            // 请求成功后的业务处理
            console.log('账单数据获取成功');
            // 更新标记为已执行
            $rootScope.hasFetchedBills = true;
        }).catch(function(error) {
            // 处理错误:如果需要允许重试,这里不要更新标记
            console.error('请求失败:', error);
        });
    }
});

注意:尽量不要滥用$rootScope避免全局污染,如果只是这个控制器需要该逻辑,方案2会更优雅。

方案2:使用单例服务存储状态(推荐,符合AngularJS最佳实践)

AngularJS的服务是单例模式,整个应用中只会实例化一次,非常适合存储这种全局状态,还能复用数据:

第一步:创建单例服务

aldro_app.service('BillDataService', function($http) {
    var hasFetched = false;
    var cachedBillData = null;

    this.fetchLatestBill = function(contractId) {
        if (!hasFetched) {
            var url = "http://api/url";
            return $http({
                url: url,
                method: 'POST',
                data: { id: contractId }
            }).then(function(response) {
                cachedBillData = response.data;
                hasFetched = true;
                return cachedBillData;
            });
        }
        // 如果已请求过,直接返回缓存的数据
        return Promise.resolve(cachedBillData);
    };
});

第二步:在控制器中依赖该服务

aldro_app.controller('ctrInicio', function ($scope, BillDataService) {
    var id = parseInt(getVariable("idcontrato"));
    
    // 调用服务方法,请求只会执行一次
    BillDataService.fetchLatestBill(id).then(function(data) {
        // 将数据绑定到视图
        $scope.billData = data;
    }).catch(function(error) {
        console.error('获取账单失败:', error);
    });
});

这种方式不仅能保证请求仅执行一次,还能缓存结果,其他控制器需要相同数据时也可以直接复用,完全符合模块化思想。

方案3:使用本地存储(适合页面刷新后仍保持状态的场景)

如果希望即使页面刷新,请求也不会重复执行,可以用localStorage或者sessionStorage:

aldro_app.controller('ctrInicio', function ($scope, $http) {
    // 加上合同ID作为键的后缀,避免不同合同的状态冲突
    var requestFlagKey = 'hasFetchedBill_' + getVariable("idcontrato");
    var hasFetched = localStorage.getItem(requestFlagKey) === 'true';

    if (!hasFetched) {
        var id = parseInt(getVariable("idcontrato"));
        var url = "http://api/url";
        
        $http({
            url: url,
            method: 'POST',
            data: { id: id }
        }).then(function(response) {
            $scope.billData = response.data;
            // 标记请求已完成
            localStorage.setItem(requestFlagKey, 'true');
            // 可选:缓存数据到本地,下次直接读取
            localStorage.setItem('cachedBill_' + id, JSON.stringify(response.data));
        }).catch(function(error) {
            console.error('请求失败:', error);
        });
    } else {
        // 从本地缓存读取已获取的数据
        var id = parseInt(getVariable("idcontrato"));
        $scope.billData = JSON.parse(localStorage.getItem('cachedBill_' + id));
    }
});

方案4:路由resolve(如果用路由管理视图)

如果你用的是ngRoute或者ui-router,可以在路由配置中通过resolve预先加载数据,这样数据只会在路由首次激活时获取一次:

以ngRoute为例:

aldro_app.config(function($routeProvider) {
    $routeProvider.when('/inicio', {
        templateUrl: 'inicio.html',
        controller: 'ctrInicio',
        resolve: {
            latestBill: function($http) {
                var id = parseInt(getVariable("idcontrato"));
                var url = "http://api/url";
                // 这里的请求只会在首次进入该路由时执行
                return $http({
                    url: url,
                    method: 'POST',
                    data: { id: id }
                }).then(function(response) {
                    return response.data;
                });
            }
        }
    });
});

// 控制器中直接注入resolve返回的结果
aldro_app.controller('ctrInicio', function ($scope, latestBill) {
    $scope.billData = latestBill;
    // 后续视图逻辑直接使用数据即可
});

这种方式的好处是,数据加载完成后才会渲染视图,避免页面出现空数据的情况。


内容的提问来源于stack exchange,提问作者Jaime Cuellar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 10:01:11