环境条件:

  • cocoscreator
  • nodejs
  • 认证公众号appid与appsecret
  • 备案域名

流程:

  1. 前端拉取授权,拿到code,交给后端nodejs处理;
  2. 后端拿到code,换取access_token与openid;
  3. 换取到access_token与openid,再申请用户信息,并返回给前端;

相关链接:

微信开发文档微信测试公众号申请

1. cocoscreator拉取授权:

// <a href="https://xiaowo6.cn/t/微信登录.html" >微信登录</a>事件
onClickTest(event,customEventData){
    Global.AudioManager.playSound();

    //获取当前页面地址作为回调地址
    let local = encodeURIComponent(window.location.origin); 
    let _appid = '申请到的appid'
    //通过微信官方接口获取code之后,会重新刷新设置的回调地址【redirect_uri】
    window.location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${this._appid}&redirect_uri=${local}&response_type=code&scope=snsapi_userinfo&state=1#wechat_redirect";`
}

2. cocoscreator授权获取code:

成功授权后,微信会跳转到回调页面redirect_uri,并携带code参数,这里在onLoad中将code取出发给后端;

onLoad () {
    function urlParse() {
        var params = {};
        if(window.location == null){
            return params;
        }
        var name,value; 
        var str=window.location.href; //取得整个地址栏
        var num=str.indexOf("?") 
        str=str.substr(num+1); //取得所有参数   stringvar.substr(start [, length ]
        
        var arr=str.split("&"); //各个参数放到数组里
        for(var i=0;i < arr.length;i++){ 
            num=arr[i].indexOf("="); 
            if(num>0){ 
                name=arr[i].substring(0,num);
                value=arr[i].substr(num+1);
                params[name]=value;
            } 
        }
        return params;
    };
    
    // 获取地址栏所携带code
    let code = urlParse().code;
    if (code){
       if (code == 'false') return;
        this.ui_label.string = JSON.stringify(code);
        // 发送给后端
        this.getaccess_token(code);
         // 重新设置code,防止被刷新
        window.history.replaceState(null, '','?code=false');
    }
}

3. nodejs获取code:

此处新建一个nodejs项目

  1. 初始化项目,生成package.json文件
npm init
  1. 安装依赖,这里用express,虽老但好用点
npm install express
  1. 新建http.js文件,简单封装下后端请求微信api,放到新建utils文件夹中,代码如下:
/**
 * utils/http.js
 */
var http = require('http');
var https = require('https');
var qs = require('querystring');

String.prototype.format = function(args) {
    var result = this;
    if (arguments.length > 0) {
        if (arguments.length == 1 && typeof (args) == "object") {
            for (var key in args) {
                if(args[key]!=undefined){
                    var reg = new RegExp("({" + key + "})", "g");
                    result = result.replace(reg, args[key]);
                }
            }
        }
        else {
            for (var i = 0; i < arguments.length; i++) {
                if (arguments[i] != undefined) {
                    var reg = new RegExp("({)" + i + "(})", "g");
                    result = result.replace(reg, arguments[i]);
                }
            }
        }
    }
    return result;
};

exports.post = function (host,port,path,data,callback) {
    
    var content = qs.stringify(data);  
    var options = {  
        hostname: host,  
        port: port,  
        path: path + '?' + content,  
        method:'GET'
    };  
      
    var req = http.request(options, function (res) {  
        console.log('STATUS: ' + res.statusCode);  
        console.log('HEADERS: ' + JSON.stringify(res.headers));  
        res.setEncoding('utf8');  
        res.on('data', function (chunk) {  
            callback(chunk);
        });  
    });
      
    req.on('error', function (e) {  
        console.log('problem with request: ' + e.message);  
    });  
      
    req.end(); 
};

exports.get2 = function (url,data,callback,safe) {
    var content = qs.stringify(data);
    var url = url + '?' + content;
    var proto = http;
    if(safe){
        proto = https;
    }
    var req = proto.get(url, function (res) {  
        res.setEncoding('utf8');  
        res.on('data', function (chunk) {  
            var json = JSON.parse(chunk);
            callback(true,json);
        });  
    });
      
    req.on('error', function (e) {  
        console.log('problem with request: ' + e.message);
        callback(false,e);
    });  
      
    req.end(); 
};

exports.get = function (host,port,path,data,callback,safe) {
    var content = qs.stringify(data);  
    var options = {  
        hostname: host,  
        path: path + '?' + content,  
        method:'GET'
    };
    if(port){
        options.port = port;
    }
    var proto = http;
    if(safe){
        proto = https;
    }
    var req = proto.request(options, function (res) {  
        res.setEncoding('utf8');  
        res.on('data', function (chunk) {  
            var json = JSON.parse(chunk);
            callback(true,json);
        });  
    });
      
    req.on('error', function (e) {  
        console.log('problem with request: ' + e.message);
        callback(false,e);
    });  
      
    req.end(); 
};

exports.send = function(res,errcode,errmsg,data){
    if(data == null){
        data = {};
    }
    data.errcode = errcode;
    data.errmsg = errmsg;
    var jsonstr = JSON.stringify(data);
    res.send(jsonstr);
};
  1. 新建app.js入口文件,代码如下:

var express = require('express');
var http = require("./utils/http");

var appInfo = {
    appid:"wx56c35a0941285ea0",
    secret:"c59f6b5541c507b467c8af5acf45252c",
};
var port = 3000;
var app = express();
app.listen(port,function(){
    console.log(`监听:${host}:${port}`);
});

function send(res,ret){
    var str = JSON.stringify(ret);
    res.send(str)
}

//设置跨域访问
app.all('*', function(req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "X-Requested-With");
    res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");
    res.header("X-Powered-By",' 3.2.1')
    res.header("Content-Type", "application/json;charset=utf-8");
    next();
});

app.get('/login',function(req,res){
    // 前端传过来的code
    var code = req.query.code;

    if(code == null || code == ""){
        return;
    }
    console.log('code is :',code);

    get_access_token(code,function(suc,data){
        if(suc){
            var access_token = data.access_token;
            var openid = data.openid;
            get_state_info(access_token,openid,function(suc2,data2){
                if(suc2){
                    // 获取到用户信息,这里发给前端
                    send(res,data2);                    
                }
            });
        }
        else{
            send(res,{errcode:-1,errmsg:"unkown err."});
        }
    });
});


function get_access_token(code,callback){
    var data = {
        appid:appInfo.appid,
        secret:appInfo.secret,
        code:code,
        grant_type:"authorization_code"
    };

    http.get2("https://api.weixin.qq.com/sns/oauth2/access_token",data,callback,true);
}

function get_state_info(access_token,openid,callback){
    var data = {
        access_token:access_token,
        openid:openid
    };

    http.get2("https://api.weixin.qq.com/sns/userinfo",data,callback,true);
}

4. 后端开启域名访问:

宝塔面板:依赖pm2与nginx;

  1. 拷贝刚刚的nodejs项目至服务端;
  2. pm2中新建项目,启动文件选择刚刚的app.js文件,其他会自动填充;

    1.png

  3. 映射域名,刚刚nodejs监听端口3000,这里在域名后面也得加上端口_g.xiaowo6.cn:3000_,完成后会自动新建一个静态站点(注意:服务端必须开放对应端口)
  4. 站点设置中,配置文件中
listen 3000; 改为  listen 80;

//server_name下面添加
location / {
    proxy_pass http://127.0.0.1:3000;
}

5. 配置微信公众平台后台开发设置

JS接口安全域名:用于在该域名下调用微信开放的JS接口;
授权回调页面域名:用户在网页授权页同意授权给公众号后,微信会将授权数据传给一个回调页面,回调页面需在此域名下,以确保安全可靠;

至此,就可以用域名访问API了;

点赞(1)

微信小程序

微信扫一扫体验

微信公众账号

微信扫一扫加关注

返回
顶部