微信公眾號連結自定義分享總結
微信H5自定義分享頁面總結
微信公眾號中預設的分頁頁面很難看,預設的縮圖。工作需要將他自定義為想要的形式。
具體詳情檢視微信開發者文件:微信開發者文件
第一步、公眾號需要配置
1、需要一個公眾號的 appId、appSecret 只要有公眾號,那麼這個就有。
2、在該公眾號的js安全域名配置一個域名用來做分享出去的連結。(登入微信公眾平臺---->公眾號設定---->功能設定---->js安全域名)。
3、需要開通微信分享介面(登入微信公眾平臺----> 介面許可權 ---->分享介面)
第二步、後臺準備
臨時票據:jsapi_ticket
jsapi_ticket是公眾號用於呼叫微信JS介面的臨時票據。正常情況下,jsapi_ticket的有效期為7200秒。由於獲取jsapi_ticket的api呼叫次數非常有限,頻繁重新整理jsapi_ticket會導致api呼叫受限,影響自身業務,開發者必須在自己的服務全域性快取jsapi_ticket 。
1.通過下面連結能夠獲取access_token(get請求)(有效期7200秒,開發者必須在自己的服務全域性快取access_token):
https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
2.拿上面得到的access_token後,通過下面的連結,採用http GET方式請求獲得jsapi_ticket(有效期7200秒,開發者必須在自己的服務全域性快取jsapi_ticket):
https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
成功返回如下JSON:
{
"errcode":0,
"errmsg":"ok",
"ticket":"bxLdikRXVbTPdHSM05e5u5sUoXNKd8-41ZO3MhKoyN5OfkWITDGgnr2fwJ0m9E8NYzWKVZvdVtaUgWvsdshFKA",
"expires_in":7200
}
3、獲得jsapi_ticket之後,就可以生成JS-SDK許可權驗證的簽名了。
簽名演算法
簽名生成規則如下:參與簽名的欄位包括noncestr(隨機字串), 有效的jsapi_ticket, timestamp(時間戳), url(當前網頁的URL,不包含#及其後面部分) 。對所有待簽名引數按照欄位名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字串string1。這裡需要注意的是所有引數名均為小寫字元。對string1作sha1加密,欄位名和欄位值都採用原始值,不進行URL 轉義。
即signature=sha1(string1)。 示例:
noncestr=Wm3WZYTPz0wzccnW
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg
timestamp=1414587457
url=http://mp.weixin.qq.com?params=value
步驟1. 對所有待簽名引數按照欄位名的ASCII 碼從小到大排序(字典序)後,使用URL鍵值對的格式(即key1=value1&key2=value2…)拼接成字串
jsapi_ticket=sM4AOVdWfPE4DxkXGEs8VMCPGGVi4C3VM0P37wVUCFvkVAy_90u5h9nbSlYy3-Sl-HhTdfl2fzFy1AOcHKP7qg&noncestr=Wm3WZYTPz0wzccnW×tamp=1414587457&url=http://mp.weixin.qq.com?params=value
步驟2. 對string1進行sha1簽名,得到signature:
0f9de62fce790f9a083d5c99e95740ceb90c27ed
注意事項:
1.簽名用的noncestr和timestamp必須與wx.config中的nonceStr和timestamp相同。
2.簽名用的url必須是呼叫JS介面頁面的完整URL。
3.出於安全考慮,開發者必須在伺服器端實現簽名的邏輯。
4.要注意簽名演算法是否正確-----確認簽名演算法正確,可用http://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=jsapisign 頁面工具進行校驗
總結一下就是:
先獲取:access_token
再獲取:jsapi_ticket
拼接字串後進行sha1加密得到:signature
程式碼大致如下(僅供參考):
一、fileCache.php
<?php
class FileCache
{
/**
* 快取目錄
* @var
*/
private $cache_dir;
/**
* @param $cache_dir
* @throws Exception
*/
public function __construct($cache_dir)
{
$this->cache_dir = $cache_dir;
if (!is_dir($cache_dir)) {
$make_dir_result = mkdir($cache_dir, 0755, true);
if ($make_dir_result === false) throw new Exception('Cannot create the cache directory');
}
}
/**
* 根據key獲取值,會判斷是否過期
* @param $key
* @return mixed
*/
public function get($key)
{
$cache_data = $this->getItem($key);
if ($cache_data === false || !is_array($cache_data)) return false;
return $cache_data['data'];
}
/**
* 新增或覆蓋一個key
* @param $key
* @param $value
* @param $expire
* @return mixed
*/
public function set($key, $value, $expire = 0)
{
return $this->setItem($key, $value, time(), $expire);
}
/**
* 設定包含後設資料的資訊
* @param $key
* @param $value
* @param $time
* @param $expire
* @return bool
*/
private function setItem($key, $value, $time, $expire)
{
$cache_file = $this->createCacheFile($key);
if ($cache_file === false) return false;
$cache_data = array('data' => $value, 'time' => $time, 'expire' => $expire);
$cache_data = json_encode($cache_data);
$put_result = file_put_contents($cache_file, $cache_data);
if ($put_result === false) return false;
return true;
}
/**
* 建立快取檔案
* @param $key
* @return bool|string
*/
private function createCacheFile($key)
{
$cache_file = $this->path($key);
if (!file_exists($cache_file)) {
$directory = dirname($cache_file);
if (!is_dir($directory)) {
$make_dir_result = mkdir($directory, 0755, true);
if ($make_dir_result === false) return false;
}
$create_result = touch($cache_file);
if ($create_result === false) return false;
}
return $cache_file;
}
/**
* 判斷Key是否存在
* @param $key
* @return mixed
*/
public function has($key)
{
$value = $this->get($key);
if ($value === false) return false;
return true;
}
/**
* 加法遞增
* @param $key
* @param int $value
* @return mixed
*/
public function increment($key, $value = 1)
{
$item = $this->getItem($key);
if ($item === false) {
$set_result = $this->set($key, $value);
if ($set_result === false) return false;
return $value;
}
$check_expire = $this->checkExpire($item);
if ($check_expire === false) return false;
$item['data'] += $value;
$result = $this->setItem($key, $item['data'], $item['time'], $item['expire']);
if ($result === false) return false;
return $item['data'];
}
/**
* 減法遞增
* @param $key
* @param int $value
* @return mixed
*/
public function decrement($key, $value = 1)
{
$item = $this->getItem($key);
if ($item === false) {
$value = 0 - $value;
$set_result = $this->set($key, $value);
if ($set_result === false) return false;
return $value;
}
$check_expire = $this->checkExpire($item);
if ($check_expire === false) return false;
$item['data'] -= $value;
$result = $this->setItem($key, $item['data'], $item['time'], $item['expire']);
if ($result === false) return false;
return $item['data'];
}
/**
* 刪除一個key,同時會刪除快取檔案
* @param $key
* @return mixed
*/
public function delete($key)
{
$cache_file = $this->path($key);
if (file_exists($cache_file)) {
$unlink_result = unlink($cache_file);
if ($unlink_result === false) return false;
}
return true;
}
/**
* 清楚所有快取
* @return mixed
*/
public function flush()
{
return $this->delTree($this->cache_dir);
}
/**
* 遞迴刪除目錄
* @param $dir
* @return bool
*/
function delTree($dir)
{
$files = array_diff(scandir($dir), array('.', '..'));
foreach ($files as $file) {
(is_dir("$dir/$file")) ? $this->delTree("$dir/$file") : unlink("$dir/$file");
}
return rmdir($dir);
}
/**
* 根據key獲取快取檔案路徑
*
* @param string $key
* @return string
*/
protected function path($key)
{
$parts = array_slice(str_split($hash = md5($key), 2), 0, 2);
return $this->cache_dir . '/' . implode('/', $parts) . '/' . $hash;
}
/**
* 獲取含有後設資料的資訊
* @param $key
* @return bool|mixed|string
*/
protected function getItem($key)
{
$cache_file = $this->path($key);
if (!file_exists($cache_file) || !is_readable($cache_file)) {
return false;
}
$cache_data = file_get_contents($cache_file);
if (empty($cache_data)) return false;
$cache_data = json_decode($cache_data, true);
if ($cache_data) {
$check_expire = $this->checkExpire($cache_data);
if ($check_expire === false) {
$this->delete($key);
return false;
}
}
return $cache_data;
}
/**
* 檢查key是否過期
* @param $cache_data
* @return bool
*/
protected function checkExpire($cache_data)
{
$time = time();
$is_expire = intval($cache_data['expire']) !== 0 && (intval($cache_data['time']) + intval($cache_data['expire']) < $time);
if ($is_expire) return false;
return true;
}
}
二、KktWxjs.php
<?php
header('Access-Control-Allow-Origin:*');//允許跨域
header('Access-Control-Allow-Methods:POST,GET');//允許的請求
header("Content-Type:application/json/json");
require_once("fileCache.php");
class wxjs{
private static $appId = "wxc*********21";
private static $appSecret = "4c7**************79b";
public function getTicekt(){
$ticket = '';
$diffTime = 0;
//現在的時間戳
$date = strtotime(date("Y-m-d H:i:s"));
//獲取快取資訊
$cache= new FileCache('cache');
if($cache->has('jsapi_ticket')){
$ticket = $cache->get('jsapi_ticket');
$expiresIn = $cache->get('expires_in')-10;//過期時間
$create_time = $cache->get('create_time');//上次更新的時間
$diffTime = $date - strtotime($create_time);
}
if ($diffTime >= $expiresIn || !$ticket) {//判斷是否過期
$appId = wxjs::$appId; //微信appid
$appSecret = wxjs::$appSecret; //微信金鑰
// 參考以下文件獲取access_token(有效期7200秒,開發者必須在自己的服務全域性快取access_token)
// https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET
$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . $appId . "&secret=" . $appSecret; //獲取token的url
$dataToken = wxjs::requestGet($url); //curl獲取access_token
$token = $dataToken['access_token']; //新的access_token
$expires = $dataToken['expires_in']; //新的過期時間
// 用第一步拿到的access_token 採用http GET方式請求獲得jsapi_ticket(有效期7200秒,開發者必須在自己的服務全域性快取jsapi_ticket):
// https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=ACCESS_TOKEN&type=jsapi
$urlTicket = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" . $token . "&type=jsapi"; //獲取ticket的url
$dataTicket = wxjs::requestGet($urlTicket);
$ticket = $dataTicket['ticket'];
// 服務全域性快取jsapi_ticket 、expires_in 、create_time
$cache->set("jsapi_ticket",$ticket);
$cache->set("expires_in",$expires);
$cache->set("create_time",$create_time = date("Y-m-d H:i:s"));
} else {
$ticket = $ticket;
}
return $ticket;
}
// 通過該介面獲取access_token、和 jsapi_ticket
public static function requestGet($url = '')
{
if (empty($url)) {
return false;
}
$curl = curl_init(); //初始化
curl_setopt($curl, CURLOPT_URL, $url); //設定抓取的url
curl_setopt($curl, CURLOPT_HEADER, 0); //設定標頭檔案的資訊作為資料流輸出
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); //設定獲取的資訊以檔案流的形式返回,而不是直接輸出。
$data = curl_exec($curl); //執行命令
curl_close($curl); //關閉URL請求
$data = json_decode($data, true);
return $data;
}
// 獲得jsapi_ticket之後,就可以生成JS-SDK許可權驗證的簽名了。
public function wxDataFormat($url){
$str="QWER*************7890";
$nonce = str_shuffle($str);//隨機字串
$timestamp = strtotime(date("Y-m-d H:i:s")); //現在的時間戳
$ticket = $this->getTicekt();
$str = "jsapi_ticket=".$ticket."&noncestr=".$nonce."×tamp=".$timestamp."&url=".$url;
$signature = sha1($str);
// echo $str;
$data = array("noncestr"=>$nonce,"timestamp"=>$timestamp,"signature"=>$signature);
return $data;
}
}
$poststr = file_get_contents("php://input");
$post = json_decode($poststr,true);
$url = $post['url'];
$wx = new wxjs();
$data = $wx->wxDataFormat($url);
$data = json_encode($data,true);
$response = '{"data":'.$data.',"statusMsg":"成功","statusCode":200}';
echo $response;
三、 第三步前端工作
通過介面獲取配置資訊 —用來簽名 -----通過config介面注入許可權驗證配置
Axios.post("http://******/WXJsInfo.php", {
url: window.location.href.split("#")[0]
})
.then(res => {
let data = res.data.data; // PS: 這裡根據你介面的返回值來使用
wx.config({
debug: false, // 開啟除錯模式
appId: "wx9********5cf", // 必填,公眾號的唯一標識
timestamp: data.timestamp, // 必填,生成簽名的時間戳
nonceStr: data.noncestr, // 必填,生成簽名的隨機串
signature: data.signature, // 必填,簽名,見附錄1
jsApiList: [
"updateAppMessageShareData",
"updateTimelineShareData",
"onMenuShareAppMessage",
"onMenuShareTimeline",
"hideMenuItems"
] // 必填,需要使用的JS介面列表,所有JS介面列表見附錄2
}); 20.
})
2.通過wx.ready來檢查簽名是否成功
wx.ready(function(){
注意:
// config資訊驗證後會執行ready方法,所有介面呼叫都必須在config介面獲得結果之後,config是一個客戶端的非同步操作,所以如果需要在頁面載入時就呼叫相關介面,則須把相關介面放在ready函式中呼叫來確保正確執行。對於使用者觸發時才呼叫的介面,則可以直接呼叫,不需要放在ready函式中。
});
wx.error(function(res){
// config資訊驗證失敗會執行error函式,如簽名過期導致驗證失敗,具體錯誤資訊可以開啟config的debug模式檢視,也可以在返回的res引數中檢視,對於SPA可以在這裡更新簽名。
});
3.檢查是否用權利呼叫相應的介面
wx.checkJsApi({
jsApiList: ['chooseImage'], // 需要檢測的JS介面列表,所有JS介面列表見附錄2,
success: function(res) {
// 以鍵值對的形式返回,可用的api值true,不可用為false
// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
}
});
完整程式碼:
wxShare.js
const wxShare = {
wxRegister(axiosUrl,title, desc, link, imgUrl) {
//axiosUrl:後端提供的連結,用來獲取JS-SDK許可權驗證的簽名等資訊 這裡就是http://*******/KktWxjs.php檔案 (必須與當前頁面同源)
//title:自定義名稱
//des:自定義描述
//link:分享的連結(必須是js安全域名)
//imgUrl:圖片連結
axios.post(axiosUrl, {
url: window.location.href
})
.then(res => {
let data = res.data.data; // PS: 這裡根據你介面的返回值來使用{noncestr:"R7AG3**************YCVLPH2W8UI",signature:"765f0618f********82f7e2621d2e59c",timestamp:160***302}
wx.config({
debug: false, // 開啟除錯模式
appId: "wxcc617f1932e74a21", // 必填,公眾號的唯一標識
timestamp: data.timestamp, // 必填,生成簽名的時間戳
nonceStr: data.noncestr, // 必填,生成簽名的隨機串
signature: data.signature, // 必填,簽名,見附錄1
jsApiList: [
"updateAppMessageShareData",
"updateTimelineShareData",
"onMenuShareAppMessage",
"onMenuShareTimeline",
"hideMenuItems"
] // 必填,需要使用的JS介面列表,所有JS介面列表見附錄2
});
wx.checkJsApi({
jsApiList: ["onMenuShareAppMessage", "onMenuShareTimeline"], // 需要檢測的JS介面列表,所有JS介面列表見附錄2,
success: function (res) {
// 以鍵值對的形式返回,可用的api值true,不可用為false
// 如:{"checkResult":{"chooseImage":true},"errMsg":"checkJsApi:ok"}
console.log(res);
// 分享給好友
wx.onMenuShareAppMessage({
title: title,
desc: desc,
link: link, //必須和當前頁面同源
imgUrl: imgUrl,
trigger: function () {
// 不要嘗試在trigger中使用ajax非同步請求修改本次分享的內容,因為客戶端分享操作是一個同步操作,這時候使用ajax的回包會還沒有返回
// alert("使用者點選傳送給朋友");
},
success: function () {
alert("分享成功");
that.hideMask = "none";
that.clientCount = 0;
that.requestClientCount(0);
},
cancel: function () {
alert("分享失敗");
},
fail: function () {
alert("分享失敗");
}
});
// 分享給朋友圈
wx.onMenuShareTimeline({
title: title,
link: link,
imgUrl: imgUrl,
trigger: function () {
// 不要嘗試在trigger中使用ajax非同步請求修改本次分享的內容,因為客戶端分享操作是一個同步操作,這時候使用ajax的回包會還沒有返回
// alert("使用者點選傳送給朋友");
},
success: function () {
alert("分享成功");
setTimeout(function () {
//回撥要執行的程式碼
that.hideMask = "none";
that.clientCount = 0;
that.requestClientCount(0);
}, 500);
},
cancel: function () {
alert("分享失敗");
},
fail: function () {
alert("分享失敗");
}
});
}
});
//簽名成功後呼叫的方法
wx.ready(function () {
//需在使用者可能點選分享按鈕前就先呼叫
// alert("簽名成功");
});
// 簽名失敗呼叫的介面
wx.error(function () {
// config資訊驗證失敗會執行error函式,如簽名過期導致驗證失敗,具體錯誤資訊可以開啟config的debug模式檢視,也可以在返回的res引數中檢視,對於SPA可以在這裡更新簽名。
alert("簽名失敗");
});
})
.catch(error => {
console.log("配置出錯", error);
});
}
};
呼叫
<script src="http://******/wxShare/weixin-js-sdk.js"></script>
<script src="http://******/wxShare/axios.js"></script>
<script src="http://******/wxShare/wxShare.js"></script>
//自定義微信分享
wxShare.wxRegister('http://******/KktWxjs.php','自定義名稱','自定義描述','自定義連結',"自定義圖片連結");
相關文章
- 公眾號新增自定義連結
- 微信公眾號,H5自定義分享H5
- 小麥苗微信公眾號文章連結地址
- TNW-微信公眾號自定義選單TNW
- vue專案使用微信公眾號支付總結Vue
- 微信開啟淘寶連結,公眾號選單欄放淘寶連結
- 公眾號軟體連結
- Vue history 路由模式微信自定義分享總結Vue路由模式
- 微信公眾號開發-分享
- 微信公眾號測試號開發小結
- 微信公眾號開發5-自定義選單-微信開發phpPHP
- 如何使用短連結工具在微信公眾號中埋點統計連結點選量
- 如何利用微狗仔實現微信自定義分享卡片連結
- 微信程式開發系列教程(四)使用微信API建立公眾號自定義選單API
- 國慶節微信公眾號活動分享,如何做好十一國慶節微信公眾號活動
- 微信公眾號排版 | 彙總和實戰
- 微信公眾號jssdk分享功能通用寫法JS
- 微信公眾號智慧回答
- 微信公眾號開發
- 微信公眾號系統
- 微信公眾號--入門
- 微信公眾平臺開發(十) 訊息回覆總結
- 自定義view總結View
- 微信公眾號投票活動製作教程 微信公眾號投票怎麼弄?
- 微信公眾號 檢視地址
- 微信公眾號介面導讀
- .net開發微信公眾號
- 微信公眾號支付全解析
- 【前端】微信公眾號推薦前端
- 微信開發之公眾號
- 【解決】小程式|微信公眾號授權給第三方平臺時報“沒有繫結公眾號”
- Python 抓取微信公眾號賬號資訊Python
- [微信公眾號] 配置與應用
- 【微信公眾號】配置與應用
- 爬取微信公眾號文章工具
- 微信公眾號-入門的坑
- 微信公眾號下發紅包 -- PHPPHP
- Nodejs微信公眾號開發NodeJS