1. 程式人生 > >【原創】配置微信伺服器與內網穿透--轉載請註明出處

【原創】配置微信伺服器與內網穿透--轉載請註明出處

微信公眾號開發

在進行學習微信公眾號開發時,首先我們需要做好一些必須的準備。

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是可以多次獲取,且在後一次獲取後,前一次依然有效的。