1 Star 0 Fork 0

618859/wx_gzh_qrcode_node_html

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
app.js 19.90 KB
一键复制 编辑 原始数据 按行查看 历史
618859 提交于 2023-05-14 12:54 . first commit
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645
/*
* @Descripttion: unTitle
* @Author: yizheng.yuan
* @Date: 2021-11-01 11:01:21
* @LastEditors: yizheng.yuan
* @LastEditTime: 2022-01-02 15:27:44
*/
// 一定要仔细看下面的文字:
/**
* 2022.12.11 我用测试号
* 1.修改appId,appsecret,token
* 2.用natapp内网穿透80端口得到地址
* 3.接口配置信息修改
* 4.JS接口安全域名修改
* 5.扫码关注了,测试号二维码
* 6.体验接口权限表:网页授权获取用户基本信息修改:域名ayuzek.natappfree.cc
*
* 7.正式账号:网页授权获取用户基本信息 获得条件:
* 个人订阅号无法开通此接口
* 公司营业执照 服务号必须通过微信认证
*/
// 使用过程中有任何问题,记得加我微信号 yizheng369问我
// 这里面会出现各种问题的。
// 在启动项目之前,要运行 npm i
// 接着要运行 npm i request
// 最后启动后台:方法1:,运行 node app.js
// 最后启动后台:方法2:,运行 nodemon app.js(如果你还没安装nodemon就要先运行这句 npm i nodemon -g )
// 问题点1:ngrok必须要通过--authtoken参数登录,才能通过微信token验证,否则不行
// (你必须要拥有一个ngrok账号,或者用github账号登录也行,没有的就去注册)
// 这样运行 ngrok.exe http 8090 --authtoken 1V46bLRGCfv5GK0WhTVmfNgXFaX_37oyzuEBkUSzbCKKcL2RQ
// 注意:这里建议用natapp进行内网穿透代替ngrok,因为ngrok经常出现异常
// natapp的使用视频:https://www.bilibili.com/video/BV19T4y1U7yG/?spm_id_from=333.337.search-card.all.click&vd_source=125d808bbbad2b8400f221b816a0f674
// 问题点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&timestamp=1648654864&unique_k=U06F2iS
const fs = require("fs");
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 app = express();
const port = 80;
const staticUrl = 'html';
const allLoginArr = []; // 所有扫码登录的人
// 解析 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}))
// 参考文章:https://cloud.tencent.com/developer/article/1679242
// 在Node.JS的app.js或者server.js中,在bodyparser中修改这个限制即可:
app.use(bodyParser.json({limit:'100mb'}));
app.use(bodyParser.urlencoded({ limit:'100mb', extended: true }));
// 返回对象
let gRel = {
error: 0,
msg: "ok",
data: ""
}
let ngRel = {
error: 1,
msg: "fail",
data: ""
}
// 工具类
const { getXMLStr ,getJsData, getObjData} = require('./utils/tool')
// 服务器地址
const serverUrl = 'http://yizheng.mynatapp.cc';
// 获取个人信息回调地址
const userInfo_redirect_url = `${serverUrl}/login.html`;
// 测试号配置:记得你们要改成你们自己的公众号上面的
const wxConfig = {
appId: 'wx3680aee5b396cc0f', // 这个要改成你自己的
appsecret: '626c988a2e4af8cc459424187951792e', // 这个也要改成你自己的
token: '123456', // 这个是你自己随便写的,写成123abc也行
serverUrl: serverUrl,
userInfo_redirect_url: userInfo_redirect_url
}
// 有效期
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(`/${staticUrl}`, express.static(staticUrl));
// 扫码登录
app.get('/html/Login', (req, res) => {
console.log('有人来问是否登录', req.query);
const { myid } = req.query
res.send(allLoginArr.includes(myid))
})
/**
* 上传图片
*/
app.post('/wx_upload_img', async (req, res) => {
// 参考 https://www.cnblogs.com/lxz123/p/15093004.html
console.log('数据code1:', req.body.openid);
let data = req.body
// 将数据保存到json文件里
let arr = require('./db.json')
let hasOne = false;
for(let i=0;i<arr.length;i++){
if(arr[i].openid == data.openid){
arr[i] = Object.assign(arr[i], data);
hasOne = true;
break;
}
}
if(!hasOne){
arr.push(data)
}
// 将数据写回到文件里
fs.writeFileSync("./db.json", JSON.stringify(arr, null, 2))
let backRel = Object.assign({}, gRel)
backRel.msg = "上传图片成功"
res.send(backRel)
})
/**
* 获取个人详细数据
*/
app.post('/getMyData', async (req, res) => {
// 参考 https://www.cnblogs.com/lxz123/p/15093004.html
console.log('数据code1:', req.body.openid);
let data = req.body
// 将数据保存到json文件里
let arr = require('./db.json')
let hasOne = false;
for(let i=0;i<arr.length;i++){
if(arr[i].openid == data.openid){
hasOne = arr[i];
break;
}
}
let backRel = Object.assign({}, gRel)
backRel.data = hasOne
res.send(backRel)
})
/**
* 获取配置信息
*/
app.get("/getConfig", (req,res)=>{
console.log('进来:',Date.now());
res.send(wxConfig)
})
// 获取用户信息,三部曲
// 感谢网友的文章 https://blog.csdn.net/qq_39506978/article/details/109410343
// 参考微信官方文档:https://developers.weixin.qq.com/doc/offiaccount/OA_Web_Apps/Wechat_webpage_authorization.html#3
app.get("/login.html", (req, res) => {
console.log(Date.now()+':login.html页面响应--用户,有信息 :', req.body, req.query);
// 如果是获取用户信息的回调,就重定向
if(req.query && req.query.code){
let code = req.query.code
res.redirect(`/${staticUrl}?code=`+code)
}
})
// 通过后台,获取用户信息1 java 前端拉起授权页面,用户授权,拿到code,再次请求用户信息
app.get("/getUserInfo", (req,res)=>{
let code = req.query.code
// 通过code,获取用户信息
let url = `https://api.weixin.qq.com/sns/oauth2/access_token?appid=${wxConfig.appId}&secret=${wxConfig.appsecret}&code=${code}&grant_type=authorization_code`
request(url, async function (error, response, body) {
if (!error) {
console.log('openId_成功_用户信息:error, response, body', typeof body)
// 最后获取用户信息
let userInfo = await getUserInfo(JSON.parse(body))
console.log('userInfo',userInfo);
res.send(userInfo)
} else {
console.log('error:', error)
res.send(JSON.parse(error))
}
});
})
// 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": "",
"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": "",
"expires_in": 7200
}
/**
* 获取微信公众号二维码--扫码登录
* 2022-03-27
*
*/
app.post('/getQrCode', async (req, res) => {
// 参考 https://www.cnblogs.com/lxz123/p/15093004.html
console.log('getQrCode数据:', req.body);
if(!access_token_obj.access_token){
console.log('access_token_obj.access_token,尚不存在,现在要先获取');
// 等待拿到为止
access_token_obj = await getNewToken()
}
let data = req.body
let ticketObj = await getQr_ticket(data)
console.log('ticketObj数据', ticketObj);
res.send(ticketObj)
})
/**
* 获取用户信息时,需要配置的微信回调地址,在授权表格右侧配置
*/
app.post('/wxback', async (req, res) => {
// 参考 https://www.cnblogs.com/lxz123/p/15093004.html
console.log('获取用户信息时-微信回调:', req.body);
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)
}
});
})
}
// 注意这个是post请求,作为试验的 2022.12.11 回顾
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}/${staticUrl}/`
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_verify_4PEd2oiCAfH93OeQ.txt',async (req,res)=>{
res.sendFile(path.resolve(__dirname,'./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}/`
}
console.log("obj2",obj2)
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('get请求:根路径,有信息 :', req.body, req.query);
// 解构参数
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.query);
let { signature, echostr, timestamp, nonce } = req.query;
let relStr = getValidateStr(req)
if (relStr == signature) {
console.log('信息来自微信服务器--');
// 提取信息
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);
if(msgObj && msgObj.EventKey){
let EventKey = msgObj.EventKey;
// 如果是第一次扫码关注是返回 EventKey: 'qrscene_47338'
if(EventKey.includes('_')){
EventKey = EventKey.split('_')[1]
}
allLoginArr.push(EventKey);
if(allLoginArr.length>30){
allLoginArr = allLoginArr.slice(10)
}
console.log('allLoginArr',allLoginArr);
}
// 回复信息给 微信服务器
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 = '你可以发送: 1,2,3,爱你!'
}
}
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&timestamp=1648654864&unique_k=U06F2iS
} else {
console.log('信息来历不明--');
}
})
app.listen(port, () => {
console.log('server open at: http://localhost:' + port);
})
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/618859/wx_gzh_qrcode_node_html.git
[email protected]:618859/wx_gzh_qrcode_node_html.git
618859
wx_gzh_qrcode_node_html
wx_gzh_qrcode_node_html
master

搜索帮助