微信公衆號開發教程02:獲取access_token

1、access_token簡介

access_token是公衆號接口調用的憑據,公衆號調用各接口時均需使用access_token。
html

例如:
java

1)建立自定義菜單接口:https://api.weixin.qq.com/cgi-bin/menu/create?access_token=ACCESS_TOKEN json

2)獲取素材列表接口:https://api.weixin.qq.com/cgi-bin/material/batchget_material?access_token=ACCESS_TOKEN api

3)獲取用戶基本信息接口:https://api.weixin.qq.com/cgi-bin/user/info?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN 緩存

等等,這些接口的請求地址均須要一個ACCESS_TOKEN參數,該參數就須要調用獲取access_token接口來獲取服務器

注意:微信

1)access_token有時效性,當前有效時間爲7200秒,須要的存儲空間爲512個字符空間,須要注意的是,微信後期有可能會改這個access_token的過時時間併發

2)若是在佈署中有多臺業務邏輯服務器均在本身的程序中獲取access_token,這將形成屢次刷新access_token的狀況,建議佈署中經過一臺中控服務器來統一獲取,或者將access_token存入緩存中統一讀取app


2、access_token獲取方式

一、接口請求地址:ide

http請求方式: GET
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

二、請求參數說明:

參數 是否必須 說明
grant_type 獲取access_token固定爲client_credential
appid 第三方用戶惟一任證
secret 第三方用戶惟一任證密鑰

注:appid和secret對應的是公衆平臺後臺中,【開發】選項中的【基本配置】中AppID和AppSecret

三、返回說明:

1)成功

{"access_token":"ACCESS_TOKEN","expires_in":7200}

2)失敗

{"errcode":40013,"errmsg":"invalid appid"}


3、access_token獲取代碼實現

下面是access_token獲取的java實現,注該代碼中json解析使用到了阿里巴巴的fastjson

package cn.kolbe.wechat.util;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;

/**
 * 獲取微信accessToken
 * @author admin
 *
 */
public class AccessTokenUtil {
	
	private static final String APP_ID = "xxxxxxx";
	private static final String APP_SECRET = "xxxxxx";
	// 當前程序使用的accessToken
	private static String accessToken = "";
	// 微信獲取accessToken的接口地址
	private static final String GET_ACCESS_TOKEN_API = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + APP_ID + "&secret=" + APP_SECRET;
	// accessToken的過時時效
	private static final int EXPIRED_SECONDS = 7200;
	// 當前最後更新accessToken的日期
	private static Date latestDate = new Date();
	
	/**
	 * 獲取accessToken
	 * @return
	 */
	public static String getToken() {
		Date now = new Date();
		if((now.getTime() - latestDate.getTime()) < EXPIRED_SECONDS*1000 && !accessToken.equals("")) {
			System.out.println("已經存在accessToken," + accessToken);
			return accessToken;
		} else {
			// 防止併發環境下,重複更新accessToken
			synchronized(AccessTokenUtil.class) {
				if((now.getTime() - latestDate.getTime()) < EXPIRED_SECONDS*1000 && !accessToken.equals("")) {
					System.out.println("accessToken已經被更新過," + accessToken);
					return accessToken;
				}
				System.out.println("accessToken過時,從新生成," + accessToken);
				latestDate = new Date();
				JSONObject json = JSON.parseObject(sendGet(GET_ACCESS_TOKEN_API));
				accessToken = json.getString("access_token");
				return accessToken;
			}
		}
	}
	
	
	/**
	 * 簡易發送Http的Get請求
	 * @param urlStr
	 * @return
	 */
	private static String sendGet(String urlStr) {
		URL url = null;
		URLConnection conn = null;
		BufferedReader reader = null;
		try {
			url = new URL(urlStr);
			conn = url.openConnection();
			conn.connect();
			reader = new BufferedReader(new InputStreamReader(conn.getInputStream(),"utf-8"));
			StringBuilder result = new StringBuilder();
			String s = new String();
			while((s = reader.readLine()) != null) {
				result.append(s);
			}
			return result.toString();
		} catch(Exception e) {
			e.printStackTrace();
			return null;
		} finally {
			try {
				reader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
	/**
	 * 測試併發環境下,獲取accessToken
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		ExecutorService executor = Executors.newCachedThreadPool();
		for(int i = 0; i < 100; i++) {
			if(i % 10 == 0) {
				Thread.sleep(1000);
			}
			executor.submit(new AccessTokenUtil.AccessTokenThread());
		}
	}
	
	/**
	 * 模擬併發環境下,獲取accessToken
	 * @author admin
	 *
	 */
	public static class AccessTokenThread implements Runnable {

		@Override
		public void run() {
			AccessTokenUtil.getToken();
		}
		
	}
	
}


注:

1)該代碼中並無考慮錯誤狀況下的處理方式(建議提供一個強制刷新accessToken的方法)

2)刷新accessToken時,須要注意考慮併發狀況下,同時多個線程發現accessToken過時,重複去刷新accessToken的狀況,代碼中已經經過加鎖來防止這種狀況的發生

相關文章
相關標籤/搜索