【原創】配置微信伺服器與內網穿透--轉載請註明出處
微信公眾號開發
在進行學習微信公眾號開發時,首先我們需要做好一些必須的準備。
1.具有一個自己的公眾號平臺,方便進行學習。
2.在網上找一款內網穿透器,進行內網穿透,接入微信開發。
3.有一個已經搭建好的Web專案。
1.申請微信公眾號
進行微信公眾號申請時,在下方地址進行申請即可,我們申請時可以根據自己的不同需求進行申請,選擇訂閱號或者服務號。企業號的開發模式和微信公眾號類似,但是必須由企業才能進行申請。
https://mp.weixin.qq.com/cgi-bin/registermidpage?action=index&lang=zh_CN
這裡不對申請做過多描述,按照表單填寫即可,很簡單。
2.使用內網穿透器進行內網穿透
免費的內網穿透器有很多,博主使用過的有花生殼和Ngrok,這裡推薦使用Ngrok,花生殼速度很慢,而且自身網站也有很多BUG。Ngrok的網站地址如下:
https://www.ngrok.cc/#down-client
申請註冊完成後,選擇登入按鈕進行登入,在左側選擇開通隧道,進入如下介面,選擇免費的版本。
選擇後進行隧道開通,可以將表單設定為如下資訊:
前置域名可以寫一個自己喜歡的域名,埠號要與本地伺服器的埠號一致。隧道名稱可以隨便起,方便自己識別。
然後我們要去下載區進行下載windows版本的客戶端。下載完成後進行解壓,可以獲得到兩個資料夾,這裡我們只保留下面一個資料夾即可。
執行該資料夾下的指令碼檔案 Sunny-Ngrok啟動工具.bat之後,可以看到如下介面
在這裡我們可以輸入隧道Id,隧道Id可以在穿透器的管理介面獲得,即下方的隧道Id
隨後將隧道Id填寫指令碼中,如果需要啟動多個隧道,則以逗號進行分割,啟動內網穿透器,不要關閉。
3.測試專案內網穿透
在專案的隧道編輯頁面可以找到如下前置域名
該域名為與我們平時專案執行時的域名localhost:8080相同,後跟專案路徑即可。
我的專案訪問名直接配置的/,可以獲得如下介面:
測試介面訪問成功後,我們的準備工作就已經完成了。
4.連線微信公眾號
我們可以進入開發者工具---開發者文件 進行檢視如何進行URL的接入
https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432
在開始開發--接入指南 中可以看到,在進行接入時,微信公眾號會向定義好的介面URL傳送get請求,引數為
signature |
微信加密簽名,signature結合了開發者填寫的token引數和請求中的timestamp引數、nonce引數。 |
timestamp |
時間戳 |
nonce |
隨機數 |
echostr |
隨機字串 |
根據微信開發文件所指出,我們可以通過對所獲得的引數進行加密處理進行校驗,如果成功則返回echostr引數,表示接入成功。這裡我們將直接返回該引數,不進行驗證。
然後進入專案,進行程式碼編寫,建立一個SpringMVC的Servlet介面:
@RequestMapping("check.do")
@ResponseBody
public String checkInterface(String signature, String timestamp, String nonce,
String echostr, HttpServletResponse response) throws IOException {
// 通過檢驗signature對請求進行校驗,若校驗成功則原樣返回echostr,表示接入成功,否則接入失敗
System.out.println(echostr);
return echostr;
}
介面編寫完成以後,我們可以在微信管理介面中,進行接入介面的配置。
我們登入進入自己所申請的微信公眾號,在最下方的開發中,有一個 基本配置 按鈕,進入頁面,進行配置我們公眾號的一系列資訊。
這裡為了便於學習,採用了明文模式,即不對來往的訊息進行加密處理。URL需要填寫我們進行接入微信公眾號的URL,token可以隨意填寫,識別驗證進行使用。EncodingAESKey使用隨機生成即可。
5.Access_token的獲取
Access_token是在微信開發中,常用的一個token引數,這個引數每天最多獲取2000次,且引數的有效期預設為7200秒。我們可以通過以下介面進行獲取:
https://api.weixin.qq.com/cgi-bin/token
grant_type |
是 |
獲取access_token填寫client_credential |
appid |
是 |
第三方使用者唯一憑證 |
secret |
是 |
第三方使用者唯一憑證金鑰,即appsecret |
該介面中,具有以上三個引數,其中grant_type直接填寫client_credential即可,後兩個引數可以在開發者配置中找到,如下圖所示
開發者密碼需要進行重置以後才能看到。看完開發者密碼以後,要注意儲存,否則無法再次檢視。我們在進行對微信公眾平臺的訪問時,需要通過httpClient進行。在新增httpClient的jar包到專案中以後,新增一個工具類:
package com.mender.mdoa.weixin.util;
import org.apache.http.HttpEntity;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class HttpUtil {
/**
* 傳送get請求到指定的URl
* @param url Url地址
* @param params 引數列表
* @return 返回的資訊
*/
public String sendGet(String url, Map<String, String> params){
StringBuffer sbUrl = new StringBuffer(url);
//1.使用預設的配置的httpclient
CloseableHttpClient client = HttpClients.createDefault();
//2.使用get方法
if(params != null && params.size() != 0){
Set<String> keys = params.keySet();
sbUrl.append("?");
for(String key : keys){
sbUrl.append(key).append("=").append(params.get(key)).append("&");
}
sbUrl.substring(0,sbUrl.length() - 1);
}
System.out.println(sbUrl.toString());
HttpGet httpGet = new HttpGet(sbUrl.toString());
InputStream inputStream = null;
CloseableHttpResponse response = null;
return this.excute(httpGet);
}
/**
* 傳送post請求到指定的URl
* @param url Url地址
* @param params 引數列表
* @return 返回的資訊
*/
public String sendPost(String url, Map<String, String> params) throws UnsupportedEncodingException {
StringBuffer sbUrl = new StringBuffer(url);
//1.使用預設的配置的httpclient
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost(sbUrl.toString());
if(params != null && params.size() > 0){
List<BasicNameValuePair> paramList = new LinkedList<BasicNameValuePair>();
Set<Map.Entry<String, String>> entrySet = params.entrySet();
for(Map.Entry<String, String> entry : entrySet){
paramList.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
}
UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList,"UTF-8");
httpPost.setEntity(entity);
}
return this.excute(httpPost);
}
/**
* 傳送資訊
* @param request
* @return
*/
private String excute(HttpUriRequest request){
InputStream inputStream = null;
CloseableHttpResponse response = null;
CloseableHttpClient httpClient = HttpClients.createDefault();
try {
response = httpClient.execute(request);
HttpEntity entity = response.getEntity();
return EntityUtils.toString(entity, "utf-8");
} catch (IOException e) {
e.printStackTrace();
return null;
}finally {
if (inputStream != null) {
try {
inputStream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (response != null) {
try {
response.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}
然後使用該工具類傳送請求到微信的access_token獲取介面即可。
如下方程式碼所示:
public static String getToken(){
String url="https://api.weixin.qq.com/cgi-bin/token";
Map<String, String> params = new HashMap<String, String>();
params.put("grant_type","client_credential");
params.put("appid","wx128a89fa44624819");
params.put("secret","a6ac12b17e8ce4b611f50c0e99571855");
HttpUtil httpUtil = new HttpUtil();
String response = httpUtil.sendGet(url, params);
System.out.println(response);
return response;
}
該方法所返回的response字串,就是一個包含了access_token的json串,從字串中提取即可。
在這裡可能會出現一下異常提示
{"errcode":40164,"errmsg":"invalid ip XXX.10.XXX.XXX, not in whitelist hint: [.L7cCA0682nfo1]"}
這裡是因為我們沒有將自己的ip地址設定到公眾號的ip地址白名單中,我們只需要將報錯資訊中的ip複製,然後新增到 微信管理中心---開發配置---白名單 中即可。
6.Access_token過期?
Access_token過期以後會跑出一個異常編碼,編碼的資訊可以在微信開發文件中進行檢視。因為Access_token具有有效期,因此我們需要每隔一段時間進行一次獲取,Access_token在獲取到下一個以後,前一個仍然是有效的,可以使用的,因此在這裡建議使用Spring的定時任務進行獲取,時間週期設定在小於兩小時即可。
我們也可以通過如下程式碼進行有效性的測試:
public static void main(String args[]) throws UnsupportedEncodingException {
String token1 = getToken();
String token2 = getToken();
Gson gson = new Gson();
Map<String, String> map = gson.fromJson(token1, HashMap.class);
token1 = map.get("access_token");
map = gson.fromJson(token2, HashMap.class);
token2 = map.get("access_token");
String address1 = getServerAddress(token1);
String address2 = getServerAddress(token2);
System.out.println(address1);
System.out.println(address2);
}
public static String getToken(){
String url="https://api.weixin.qq.com/cgi-bin/token";
Map<String, String> params = new HashMap<String, String>();
params.put("grant_type","client_credential");
params.put("appid","wx128a89fa44624819");
params.put("secret","a6ac12b17e8ce4b611f50c0e99571855");
HttpUtil httpUtil = new HttpUtil();
String response = httpUtil.sendGet(url, params);
System.out.println(response);
return response;
}
public static String getServerAddress(String token){
String url="https://api.weixin.qq.com/cgi-bin/getcallbackip";
Map<String, String> params = new HashMap<String, String>();
params.put("access_token",token);
HttpUtil httpUtil = new HttpUtil();
String response = httpUtil.sendGet(url, params);
System.out.println(response);
return response;
}
先獲取了兩個access_token然後使用這兩個access_token來獲取微信的服務地址,最後我們就可以得到這個結果。這樣可以證明access_token是可以多次獲取,且在後一次獲取後,前一次依然有效的。