微信调用接口,防止Access_token过期的方法

大家都知道,微信中调用订阅用户接口中需要Access_token,而根据微信官方文档中说明:

access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效


所以这就导致我们每次去获取订阅用户相关信息的时候都去重新取access_token。这就造成两个问题。

1. 慢,因为取access_token是远程在腾讯提供的API网址上,所以会有一定的延迟。

2. 访问次数越多,超出接口调用限制,会被腾讯限制。我就遭过。后来查API手册才知道有这句话:

默认每个公众帐号都不能超过下面的频率限制。 当超出调用接口频率限制,调用对应接口将会收到如下错误信息:

{"errcode":45009,"errmsg":"api freq out of limit"}
接口名称 频率限制
获取凭证接口 200(次/天)
自定义菜单创建接口 100(次/天)
自定义菜单查询接口 1000(次/天)
自定义菜单删除接口 100(次/天)

所以针对此问题,我想出了用文本文件或XML来存取动态的access_token。反正2小时才过期,写入又不频繁。当然你也可以存取到数据库。

同样的我用到了SAE的Storage
微信调用接口,防止Access_token过期的方法_第1张图片

然后对访问用户相关信息和得到AccessToken的类 进行了封装:
        //得到订阅用户 (返回数组)
	public function GetUserList()
	{
		$strjson = $this -> GetUrlReturn("https://api.weixin.qq.com/cgi-bin/user/get?access_token=%s");
		$openidarr= $strjson->data->openid;
		//print_r($openidarr); 调试
		return $openidarr;
	}
	
	//得到订阅用户详情(返回对象)
	public function GetUserDetail($openid)
	{
		$url = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=%s&openid={$openid}";
		$strjson = $this -> GetUrlReturn($url);
		return $strjson;
	}
	
	
	/*
	*
	*  私有成员变量 存token值
	*  因为//access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。
	*  正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效。
	*/
	private $_token ;

	/*
	*
	* 私有方法
	*
	*/
	//得到Token对象并写入到配置文件
	private function InitToken()
	{
		$url = sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",APPID, SECRET);
		//echo APPID;
		$ch = curl_init(); //创建一个新url资源
		curl_setopt($ch, CURLOPT_URL,$url);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		$a = curl_exec($ch);
		$strjson=json_decode($a);
		$token = $strjson->access_token;
		if (empty($token))
		{
			//修改 {"errcode":45009,"errmsg":"api freq out of limit"}
			echo "错误:取得token无效,可能是调用太频繁!";	  //$strjson
			throw new Exception('错误:取得token无效'); 
		}
		
		$obj = fopen("saestor://weixindata/token.txt","w+");  //SAE禁用fopen本地文件,这里需要Storage
		fwrite($obj,$token);
		$this -> _token = $token;
	}
	
	//封装私有方法,调用得到Get的参数,$needToken默认为false, 不取值,这里有一个潜规则,%s为 self::$_token
	private function GetUrlReturn($url, $needToken = false)
	{
		//第一次为空,则从文件中读取
		if (empty($this -> _token))
		{
			$obj = fopen("saestor://weixindata/token.txt","r"); 
			$this -> _token = fgets($obj,1000);
		}
		
		//为空则重新取值
		if (empty($this -> _token) || $needToken)
		{
			$this ->InitToken(); 
		}
		$newurl = sprintf($url, $this -> _token);
		$ch = curl_init();  //创建一个新url资源
		curl_setopt($ch, CURLOPT_URL,$newurl);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
		$a = curl_exec($ch);
		$strjson=json_decode($a);
		//var_dump($strjson);  //开启可调试
		if (!empty($strjson-> errcode))
		{
			switch ($strjson-> errcode){
				
				case 40001:
					$this -> GetUrlReturn($url, true); //重新取值,可能是过期导致
					break;
				case 41001:
					throw new Exception("缺少access_token参数:".$strjson->errmsg); 
					break;
				default:
					throw new Exception($strjson->errmsg); //其他错误,抛出
					break;
				
			}
		}
		return $strjson;
	}

大概意思是,默认就是从文本文件中取这个值,当这个值过期的时候,重新调用 InitToken 这个方法,获得最新的AccessToken。这样AccessToken就永远不会过期了。

这是我想到的办法,欢迎大家给出更好的方法,相互学习,相互提高。


你可能感兴趣的:(sae,微信,accesstoken)