代码拉取完成,页面将自动刷新
同步操作将从 618859/wx_jsapi 强制同步,此操作会覆盖自 Fork 仓库以来所做的任何修改,且无法恢复!!!
确定后同步将在后台操作,完成时将刷新页面,请耐心等待。
/*
* @Descripttion: unTitle
* @Author: yizheng.yuan
* @Date: 2021-11-01 11:01:21
* @LastEditors: yizheng.yuan
* @LastEditTime: 2022-01-02 15:27:44
*/
// 一定要仔细看下面的文字:
// 使用过程中有任何问题,记得加我微信号 yizheng369问我
// 这里面会出现各种问题的。
// 在启动项目之前,要运行 npm i
// 接着要运行 npm i request
// 最后启动后台:方法1:,运行 node app.js
// 最后启动后台:方法2:,运行 nodemon app.js(如果你还没安装nodemon就要先运行这句 npm i nodemon -g )
// 问题点1:建议用natapp代替ngrok,进行内网穿透。
// ngork问题太多,建议不要用。
// ngork必须要通过--authtoken参数登录,才能通过微信token验证,否则不行
// (你必须要拥有一个ngrok账号,或者用github账号登录也行,没有的就去注册)
// 这样运行 ngrok.exe http 8090 --authtoken 1V46bLRGCfv5GK0WhTVmfNgXFaX_37oyzuEBkUSzbCKKcL2RQ
// 问题点2:-跨域设置会导致返回的页面为字符串string,故不能这样设置:res.header("Content-Type", "application/json;charset=utf-8");
// 问题3:jsapi如果不完整的话,记得要【扫码关注测试公众号】,微信测试号页面找到这句话
// 提醒:这个是视频讲解过程,遇到问题是,请认真看视频 https://www.bilibili.com/video/BV1XL411T73G/
// 详细完整视频 微信公众号开发接收信息 https://m.bilibili.com/video/BV1XJ411P7T4?p=10&share_medium=iphone&share_plat=ios&share_source=WEIXIN&share_tag=s_i×tamp=1648654864&unique_k=U06F2iS
const express = require('express');
var bodyParser = require('body-parser');
var sha1 = require('sha1');
const request = require('request')
const path = require('path');
const { get } = require('request');
const requestIp = require('request-ip');
const app = express();
app.use(requestIp.mw());
const port = 80;
// 工具类
const { getXMLStr ,getJsData, getObjData} = require('./utils/tool')
// 测试号配置:记得你们要改成你们自己的公众号上面的12
const wxConfig = {
appId: 'wx77d2afd164525fb3', // 这个要改成你自己的
appsecret: 'b24535894acd5beb39912ca7af6f8fa5', // 这个也要改成你自己的
token: 'xxx' // 这个是你自己随便写的,写成123abc也行
}
const serverUrl = 'https://272v414q76.vicp.fun';
// 有效期
var enableTimestamp = 0;
// 过渡时间 提早5分钟,重新获取token
var transitionTime = 5 * 60 * 1000;
// 处理跨域
//设置跨域访问
app.all('*', function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", ' 3.2.1')
next();
})
// 处理静态资源访问
app.use('/html', express.static('html'));
// app.get('/html',(rew,res)=>{
// console.log('进来--html');
// res.sendFile(path.join(__dirname,'./html/index.html'))
// })
// 解析 application/json
app.use(bodyParser.json());
// 解析 application/x-www-form-urlencoded
app.use(bodyParser.urlencoded());
// 接收参数
// app.use(express.json())
// app.use(express.urlencoded({extended: true}))
// 1.获取token 令牌 通过postman获取即可 与视频不同
// get
// let url =`https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&
// appid=wx3680aee5b396cc0f&secret=13d16b772027b3d257b8e1ba28df9652`
// URL需要正确响应微信发送的Token验证 http://www.xcaipu.cn/weixin
// JS接口安全域名 www.xcaipu.cn/wx_js
// access_token: 令牌(有效期7200秒,开发者必须在自己的服务全局缓存access_token)
var access_token_obj = {
"access_token": "51_wy_LaL72FJc9HI1cnlRnm6kYtpjVho7tzZl4IDhBzLWsxSsRBB3tQ79KGp1f9kuoBO6JY33Ay3F4wjI94LLoVWQNsyrmLeuvuN2IkIHGxpusIfbOxcCkHwOiA5bRJubyBJj3f8KVpunx0Rl4ZUMgAJAKFX",
"expires_in": 7200
}
// 2.获取ticket:门票 通过postman获取即可 与视频不同
// ticket:门票(有效期7200秒,开发者必须在自己的服务全局缓存jsapi_ticket)
// https://api.weixin.qq.com/cgi-bin/ticket/getticket?
// access_token=51_wy_LaL72FJc9HI1cnlRnm6kYtpjVho7tzZl4IDhBzLWsxSsRBB3tQ79KGp1f9kuoBO6JY33Ay3F4wjI94LLoVWQNsyrmLeuvuN2IkIHGxpusIfbOxcCkHwOiA5bRJubyBJj3f8KVpunx0Rl4ZUMgAJAKFX&type=jsapi
var ticketObj = {
"errcode": 0,
"errmsg": "ok",
"ticket": "O3SMpm8bG7kJnF36aXbe84asaV6bl616leMYTutwmpXjnTbzL73w1zJTV5QYP0yMBkUG-I4jskS9mYbomoF4Hg",
"expires_in": 7200
}
/**
* 获取微信公众号二维码--扫码登录
* 2022-03-27
*
*/
app.post('/getQrCode', async (req, res) => {
// 参考 https://www.cnblogs.com/lxz123/p/15093004.html
console.log('数据code1:', req.body);
let data = req.body
let ticketObj = await getQr_ticket(data)
res.send(ticketObj)
})
function getQr_ticket(data) {
var url = `https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=${access_token_obj.access_token}`
return new Promise((resolve, reject) => {
request.post(
{
url,
json: data
},
async function (error, response, body) {
if (!error) {
resolve(body)
} else {
reject(JSON.parse(error))
}
}
);
})
}
// 方法写在下面
app.post('/code', (req, res) => {
console.log('数据code1:', req.body);
const { code } = req.body;
var url = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${wxConfig.appId}&secret=${wxConfig.appsecret}&code=${code}&grant_type=authorization_code`
return new Promise((resolve, reject) => {
request(url, async function (error, response, body) {
if (!error) {
console.log('openId_成功11:error, response, body', typeof body, body)
// resolve(JSON.parse(body))\
let userInfo = await getUserInfo(JSON.parse(body))
res.send(userInfo)
} else {
console.log('error:', error)
// reject(error)
res.send(JSON.parse(error))
}
});
})
})
function getUserInfo(obj) {
return new Promise((resolve, reject) => {
let url = `https://api.weixin.qq.com/sns/userinfo?access_token=${obj.access_token}&openid=${obj.openid}&lang=zh_CN`
request(url, function (error, response, body) {
if (!error) {
console.log('getUserInfo_成功:, response, body', typeof body, body)
// resolve(JSON.parse(body))\
resolve(JSON.parse(body))
} else {
console.log('error:', error)
// reject(error)
reject(error)
}
});
})
}
app.post('/getUserInfo', (req, res) => {
console.log('数据code :', req.body);
const { code } = req.body
return new Promise((resolve, reject) => {
const server = 'http://qiaolianyun.viphk.91tunnel.com/wxsss/OpenIDss'
// const server= 'http://qiaolianyun.viphk.91tunnel.com/servlet/getUserInfo';
const other_server = `${server}?code=${code}`
request(other_server, function (error, response, body) {
if (!error) {
console.log('getRight_成功11:error, response, body', typeof body, body)
// resolve(JSON.parse(body))\
res.send(JSON.parse(body))
} else {
console.log('error:', error)
// reject(error)
res.send(JSON.parse(error))
}
});
})
})
// 获取openId
// scope为snsapi_base
var redirect_uri = `${serverUrl}/html/`
var snsapi_base_Url = `https://open.weixin.qq.com/connect/oauth2/authorize?
appid=${wxConfig.appId}
&redirect_uri=${encodeURIComponent(redirect_uri)}
&response_type=code
&scope=snsapi_base
&state=123#wechat_redirect`;
function getRight(right_url) {
return new Promise((resolve, reject) => {
request(right_url, function (error, response, body) {
if (!error) {
console.log('getRight_成功11:error, response, body', typeof body, body)
resolve(true)
} else {
console.log('error:', error)
reject(error)
}
});
})
}
app.get('/getRight', async (req, res) => {
let rel = await getRight(snsapi_base_Url);
console.log('object');
res.send(rel)
})
// app.get('/mp',async (req,res)=>{
// res.sendFile(path.resolve(__dirname,'./public/MP_verify_4PEd2oiCAfH93OeQ.txt'))
// })
// 获取新的token
function getNewToken() {
return new Promise((resolve, reject) => {
let token_url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${wxConfig.appId}&secret=${wxConfig.appsecret}`;
request(token_url, function (error, response, body) {
if (!error) {
console.log('成功1:error, response, body', typeof body, body)
resolve(JSON.parse(body))
} else {
console.log('error:', error)
reject(error)
}
});
})
}
// 获取新的ticket
function getNewTicket(access_token) {
console.log('access_token', access_token);
return new Promise((resolve, reject) => {
let ticket_url = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${access_token}&type=jsapi`;
request(ticket_url, function (error, response, body) {
if (!error) {
console.log('成功2:error, response, body', body)
resolve(JSON.parse(body))
} else {
console.log('error:', error)
reject(error)
}
});
})
}
// 报错判断
// 63002: 应该是该ip不在白名单内 或者 参与加密的url跟公众号上面的测试号jsapi域名不一致导致的 请检查
// 获取微信api需要的配置参数
app.get('/wx', async (req, res) => {
// 现在
const nowTimeStamp = Date.now();
// 1.判断当前的有效期,是否有效
if ((enableTimestamp - transitionTime) < nowTimeStamp) {
console.log('过期了:重新请求---');
// 如果是在过渡时间内了,要重新请求
let rel = await getNewToken()
// 根据获取到的token,继续获取ticket
console.log('rel:', rel);
access_token_obj = rel;
ticketObj = await getNewTicket(rel.access_token);
enableTimestamp += nowTimeStamp + ticketObj.expires_in * 1000;
console.log('ticketObj:', ticketObj);
} else {
console.log('未过期--使用旧的1');
}
const obj2 = {
noncestr: (Math.random() + '').split('.')[1],
jsapi_ticket: ticketObj.ticket,
timestamp: nowTimeStamp,
url: `${serverUrl}/html/`
}
let js_arr = [
`jsapi_ticket=${obj2.jsapi_ticket}`,
`noncestr=${obj2.noncestr}`,
`timestamp=${obj2.timestamp}`,
`url=${obj2.url}`
];
let js_str = js_arr.sort().join('&')
console.log('js_str', js_str);
let signature = sha1(js_str);
console.log('signature', signature);
const config_obj = {
appId: wxConfig.appId, // 必填,公众号的唯一标识
timestamp: nowTimeStamp, // 必填,生成签名的时间戳
nonceStr: obj2.noncestr, // 必填,生成签名的随机串
signature,// 必填,签名
}
res.send(config_obj)
})
// app.get('/getAddress',(req,res)=>{
// console.log('req',req.body,req.query);
// let {url} = req.query;
// request(url, function (error, response, body) {
// if(!error){
// console.log('error, response, body', body)//打印百度首页html内容
// res.send({
// error: 0,
// data: JSON.parse(body)
// })
// }else{
// console.log('error',error)
// res.send({
// error:1,
// data: error
// })
// }
// })
// // rq.get({url, resolveWithFullResponse:true})
// // .then(res=>{
// // console.log('res',res);
// // })
// // .then(err=>{
// // console.log('err',err);
// // })
// })
// 接收信息
// app.get('/msg', (req, res) => {
// console.log(Date.now()+':根路径,有信息:', req.body, req.query);
// res.send(true)
// })
// 配合微信验证token配置方法:
app.get('/', (req, res) => {
console.log(':根路径,有信息 :', req.body, req.query, req.url);
// 解构参数
let { signature, echostr, timestamp, nonce } = req.query;
let relStr = getValidateStr(req)
// 然后和signature比较,是否一致
if (relStr === signature) {
console.log('验证通过-2--');
// res.send(true)
res.send(echostr)
} else {
console.log('验证不通过-1--');
res.send(false)
}
})
// 验证信息是否来自微信服务器
function getValidateStr(req) {
let { token } = wxConfig;
console.log('我的token:', token);
let { signature, echostr, timestamp, nonce } = req.query;
// 将 token, timestamp, nonce 三项按照字典排序
let arr = [token, timestamp, nonce];
arr = arr.sort();
console.log('sort-arr', arr);
let arrStr = arr.join('');
// 然后通过sha1加密
const relStr = sha1(arrStr);
console.log('relStr', relStr);
return relStr;
}
// 接收微信发来的消息 我傻了 居然想不到用post方法
app.post('/', async (req, res) => {
console.log('post-home:', req.url, + ',' + req.query + ',' + {...req.body});
let { signature, echostr, timestamp, nonce } = req.query;
let relStr = getValidateStr(req)
if (relStr == signature) {
console.log('信息来自微信服务器--' + req.clientIp + ',' + req.ip);
// 提取信息
let xmlData = await getXMLStr(req);
console.log('xmlData:', xmlData);
/** 微信服务器返回了的xml格式数据
<xml>
<ToUserName><![CDATA[gh_b3958963bb18]]></ToUserName>
<FromUserName><![CDATA[od4SM6Y8InFQGTfBjsiMRhkteIAE]]></FromUserName>
<CreateTime>1648658404</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[3]]></Content>
<MsgId>23603117248352202</MsgId>
</xml>
*/
// 通过工具解析xml数据
let jsData = await getJsData(xmlData)
console.log('jsData:',jsData);
// 再次优化数据
let msgObj = getObjData(jsData.xml)
console.log('msgObj:',msgObj);
// 回复信息给 微信服务器
let content = ''
if(msgObj.MsgType == 'text'){
if(msgObj.Content == 1){
content = '努力吧!'
} else if(msgObj.Content == 2){
content = '再坚持一会,就成功了'
} else if(msgObj.Content.includes('爱')){
content = '爱你一万年!'
} else {
content = '谢谢!'
}
}
else if(msgObj.MsgType == 'event'){
content = 'event事件'
if(msgObj.Event == 'SCAN'){
content = '好家伙,手机扫码'
} else if(msgObj.Event == 'subscribe'){
content = '好家伙,欢迎您的关注!'
}
if(msgObj.Event == 'unsubscribe'){
content = '好家伙,你居然敢取笑关注?'
}
}
else{
content = '其他信息来源!'
}
// 根据来时的信息格式,重组返回。(注意中间不能有空格)
let msgStr = `<xml>
<ToUserName><![CDATA[${msgObj.FromUserName}]]></ToUserName>
<FromUserName><![CDATA[${msgObj.ToUserName}]]></FromUserName>
<CreateTime>${Date.now()}</CreateTime>
<MsgType><![CDATA[text]]></MsgType>
<Content><![CDATA[${content}]]></Content>
</xml>`
res.send(msgStr)
// 非常感谢尚硅谷的视频
// 微信公众号开发接收信息https://m.bilibili.com/video/BV1XJ411P7T4?p=10&share_medium=iphone&share_plat=ios&share_source=WEIXIN&share_tag=s_i×tamp=1648654864&unique_k=U06F2iS
} else {
console.log('信息来历不明--' + req.clientIp + ',' + req.ip);
}
})
app.listen(port, () => {
console.log('server open at: http://localhost:' + port);
})
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。