A, preparation,

  1. Register for a wechat subscription account
  2. Register the applet test number
  3. Sunny-ngrok tool installation and account registration

Note: The prototype of sunny-Ngrok is Ngrok, but Ngrok is foreign, sunny-Ngrok is a domestic private server, the speed is faster, the main function is domain name forwarding, simulating public IP and port, and even can be configured for customers to display projects on the public network. Address: www.ngrok.cc/, after entering the registration to open the tunnel, there are free. Remember: a wechat can only register one wechat product, but can manage more than one.

This is my tunnel :(free if it doesn’t work, just use this)Use sunny-ngrok to try forwarding once: Download the tool, start the tool, enter the tunnel ID, and press EnterExplain 127.0.0.1:3000 has been forwarded to the public IP of zhifieji.vipgz4.idcfengye.com.

Create a weixin directory, NPM initialization:

npm init -y
Copy the code

Copy the following into package.json:

{
  "name": "weixin-lesson"."version": "1.0.0"."description": "Wechat Development"."main": "index.js"."directories": {
    "doc": "doc"
  },
  "scripts": {
    "sunny": "./bin/sunny clientid 62d16df91a118fd3"."ngrok": "./bin/ngrok http 3000"."test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git"."url": "[email protected]:web_dev/weixin-lesson.git"
  },
  "author": ""."license": "ISC"."dependencies": {
    "axios": "^ 0.18.0." "."co-wechat": "^ 2.3.0." "."co-wechat-oauth": "^ 2.0.1." "."crypto": "^" 1.0.1."express": "^ 4.16.4"."jsonwebtoken": "^ 8.4.0"."koa": "^ 2.6.2." "."koa-bodyparser": "^ 2"."koa-compress": "^ 3.0.0"."koa-jwt": "^ 3.5.1 track of"."koa-route": "^ 3.2.0"."koa-router": "^ 7.4.0"."koa-socket": "^ 4.4.0"."koa-static": "^ 5.0.0"."koa-views": "^ 6.1.5." "."koa-websocket": "^ 5.0.1." "."koa-xml-body": "^ 2.1.0." "."moment": "^ 2.23.0"."mongoose": "^ 5.4.4." "."promise-redis": "0.0.5"."pug": "^ 2.0.3"."redis": "^ 2.8.0"."request": "^ 2.88.0"."request-promise": "^ 4.2.2." "."socket.io": "^ 2.2.0." "."watch": "^ 1.0.2"."wechat": "^ 2.1.0." "."wechat-oauth": "^ 1.5.0." "."xml2js": "^ 0.4.19"}}Copy the code

Then install the dependencies

npm install
# or
yarn
Copy the code

Then create the seed directory under weixin directory, and create index.js and index.html under the seed directory.

index.js:

const Koa = require('koa')
const Router = require('koa-router')
const static = require('koa-static')
const bodyParser = require('koa-bodyparser');
const app = new Koa()
app.use(bodyParser())
const router = new Router()
app.use(static(__dirname + '/'))

app.use(router.routes()); /* Start routing */
app.use(router.allowedMethods());
app.listen(3000);
Copy the code

index.html:

<! DOCTYPEhtml>
<html>

<head>
    <title>Full stack development of wechat public account</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
    <script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://unpkg.com/cube-ui/lib/cube.min.js"></script>
    <script src="https://cdn.bootcss.com/qs/6.6.0/qs.js"></script>
    <script src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/cube-ui/lib/cube.min.css">
    <style>
        /* .cube-btn { margin: 10px 0; } * /
    </style>
</head>

<body>
    <div id="app">
        <cube-input v-model="value"></cube-input>
        <cube-button @click='click'>Click</cube-button>
    </div>
    <script>
        var app = new Vue({
            el: '#app'.data: {
                value: 'input'
            },

            methods: {
                click: function () {
                    console.log('click')}},mounted: function () {}});</script>
</body>

</html>
Copy the code

Open the terminal in the seed directory, run Nodemon (installation required), and open 127.0.0.1 on port 3000

npm install -g nodemon
nodemon
Copy the code

Said in front of the 3000 port forwarding through the ngrok to the zhifieji.vipgz4.idcfengye.com, we try open this url:

Use the message interface

Wechat has its own automatic message reply function, which can be set on the public platform, but it is too rigid to dynamically reply to messages

Enter the wechat developer tool and apply for a public platform test accountThere are some configurations, fill in the forwarding domain name, token optional, and the same server useThe URL of the interface configuration is the forwarding URL plus /wechat, and then submit the interface configuration information (you need to try more to submit successfully).

Conf. Js and add appID, appSecret, token to the seed directory:

module.exports={
    appid: 'wx77f481fc8a9113a4'.appsecret: '2b84470b9fb0f8166a8518c5b40edaf9'.token: 'qweqwe'
}
Copy the code

In index.js, use a library co-wechat, so index.js will become the following:

const Koa = require('koa')
const Router = require('koa-router')
const static = require('koa-static')
const bodyParser = require('koa-bodyparser');
const app = new Koa()
const conf = require('./conf')/ / into the conf
app.use(bodyParser())
const router = new Router()
app.use(static(__dirname + '/'))

const wechat = require('co-wechat')// Use the Co-wechat library
router.all('/wechat', wechat(conf).middleware(
    async message => {
        console.log('wechat:', message)
        return 'Hello World ' + message.Content
    }
))

app.use(router.routes()); /* Start routing */
app.use(router.allowedMethods());
app.listen(3000);
Copy the code

Libraries that begin with co- represent libraries that meet asynchronous requirements

After success, this time, you can pay attention to the following test number TWO-DIMENSIONAL code

Send 1, reply Hello World 1 (if there is no set method to get the message sent by the user, so sometimes also need API), as shown below:

Three, wechat some API calls

Related document: developers.weixin.qq.com/doc/offiacc…

Access token:

const axios = require('axios')
const tokenCache = {
    access_token:' '.updateTime:Date.now(),
    expires_in:7200
}

router.get('/getTokens'.async ctx => {/ / access token
    const wxDomain =  `https://api.weixin.qq.com`
    const path = `/cgi-bin/token`
    const param = `? grant_type=client_credential&appid={conf.appid}&secret={conf.appsecret}`
    const url = wxDomain + path + param
    const res = await axios.get(url)
    Object.assign(tokenCache,res.data,{
        updateTime:Date.now()
    })
    ctx.body = res.data
})
Copy the code

Obtaining User information

router.get('/getFollowers'.async ctx => {// Get user information
    const url = `https://api.weixin.qq.com/cgi-bin/user/get?access_token=${tokenCache.access_token}`
    const res = await axios.get(url)
    console.log('getFollowers:',res)
    ctx.body = res.data
})
Copy the code

The above is the native writing method, in fact we have ten libraries can use.

Using co – wechat – API

yarn add co-wechat-api 
Copy the code
const WechatAPI = require('co-wechat-api')
const api = new WechatAPI(
    conf.appid,
    conf.appsecret,
    / / / / take a Token
    // async () => await ServerToken.findOne(),
    / / / / Token
    // async token => await ServerToken.updateOne({}, token, { upsert: true })
)
router.get('/getFollowers'.async ctx => {
    let res = await api.getFollowers()
    res = await api.batchGetUsers(res.data.openid, 'zh_CN')// This will return the details
    ctx.body = res
})
Copy the code

Global notes

Global tickets need to be based on mongodb or Redires, we use mongodb. New a mongoose. Js

const mongoose = require('mongoose')
const {
    Schema
} = mongoose
mongoose.connect('mongodb://localhost:27017/weixin', {
    useNewUrlParser: true
}, () = > {
    console.log('Mongodb connected.. ')})exports.ServerToken = mongoose.model('ServerToken', {
    accessToken: String
});
Copy the code

Index. js with co-weike-api:

const { ServerToken } = require('./mongoose')// Global ticket source
const WechatAPI = require('co-wechat-api')
const api = new WechatAPI(
    conf.appid,
    conf.appsecret,
    / / take a Token
    async() = >await ServerToken.findOne(),
    // 存Token
    async token => await ServerToken.updateOne({}, token, { upsert: true })
)
router.get('/getFollowers'.async ctx => {
    let res = await api.getFollowers()
    res = await api.batchGetUsers(res.data.openid, 'zh_CN')
    ctx.body = res
})
Copy the code

Add a button and a button click method to index.html:

<cube-button @click='getFollowers'>getFollowers</cube-button>
Copy the code
 async getFollowers(){
      const res = await axios.get('/getFollowers')
      console.log('res',res)
},
Copy the code

Click on it :(this getFollwers gets the data)

V. Information promotion

Similar to this, mobile phone wechat scan code wechat public platform to send 1 or 2, the pie chart will automatically count the number of 1 and 2 sent. ! [] (Img – blog. Csdnimg. Cn/c25b0480ca8…=400×400) The background (emulator) will display the push of the foreground (wechat is testing the subscription number) and update echart. The code is in the Vote section below and will be released later.

Six, Oauth2 certification process

First of all, we should know that there are three ends, browser, server and wechat server.

1. The browser sends an authentication request to the server

2. The server redirects the browser to the wechat authentication interface

3. The browser requests third-party authentication from the wechat server (wechat authentication)

4. The wechat server is destroyed and a authentication code is given to the server

5. The server applies for the authentication token from the wechat server with code

6. The wechat server returns a token to the server

Finally, when the server gets the token authentication successfully, it sends a command to the browser to refresh the interface

After refreshing, there will be a user information

Use wechat developer tools, select the public account webpage, used to preview.

PS: In the above code

  1. The message pushed me into the vote directory
  2. The rest of the API call methods are placed in the SEED directory

Seven, to achieve a wechat authentication login

Js configuration interface security domain, is our public domain forwarding (without agreement) : zhifieji.vipgz4.idcfengye.comAnd each WeChat interface API will authorize the domain name, namely below change position, modify the same as above: (zhifieji.vipgz4.idcfengye.com) Make a copy of the seed directory in the previous project called seed_UP, and we’ll give the previous one seed_up! Index. Js;

const OAuth = require('co-wechat-oauth')// Introduce an oauth library
const oauth = new OAuth(conf.appid,conf.appsecret)

/** * Generates the user URL */
router.get('/wxAuthorize'.async (ctx, next) => {
    const state = ctx.query.id
    console.log('ctx... ' + ctx.href)
    let redirectUrl = ctx.href
    redirectUrl = redirectUrl.replace('wxAuthorize'.'wxCallback')
    const scope = 'snsapi_userinfo'
    const url = oauth.getAuthorizeURL(redirectUrl, state, scope)
    console.log('url' + url)
    ctx.redirect(url)
})
/** * User callback method */
router.get('/wxCallback'.async ctx => {
    const code = ctx.query.code
    console.log('wxCallback code', code)
    const token = await oauth.getAccessToken(code)
    const accessToken = token.data.access_token
    const openid = token.data.openid
    console.log('accessToken', accessToken)
    console.log('openid', openid)
    ctx.redirect('/? openid=' + openid)
})
/** * Get user information */
router.get('/getUser'.async ctx => {
    const openid = ctx.query.openid
    const userInfo = await oauth.getUser(openid)
    console.log('userInfo:', userInfo)
    ctx.body = userInfo
})
Copy the code

Index.html:

<! DOCTYPEhtml>
<html>

<head>
    <title>Full stack development of wechat public account</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=0">
    <script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
    <script src="https://unpkg.com/axios/dist/axios.min.js"></script>
    <script src="https://unpkg.com/cube-ui/lib/cube.min.js"></script>
    <script src="https://cdn.bootcss.com/qs/6.6.0/qs.js"></script>
    <script src="http://res.wx.qq.com/open/js/jweixin-1.4.0.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/cube-ui/lib/cube.min.css">
    <style>
        /* .cube-btn { margin: 10px 0; } * /
    </style>
</head>

<body>
    <div id="app">
        <cube-input v-model="value"></cube-input>
        <cube-button @click='click'>Click</cube-button>
        <cube-button @click='getTokens'>getTokens</cube-button>
        <cube-button @click='getFollowers'>getFollowers</cube-button>
        <cube-button @click='auth'>WeChat login</cube-button>
        <cube-button @click='getUser'>Obtaining User information</cube-button>
    </div>
    <script>
        var app = new Vue({
            el: '#app'.data: {
                value: 'input'
            },

            methods: {
                click: function () {
                    console.log('click')},async getTokens(){
                    const res = await axios.get('/getTokens')
                    console.log('res:',res)
                },
                async getFollowers(){
                    const res = await axios.get('/getFollowers')
                    console.log('res',res)
                },
                async auth(){
                    window.location.href = '/wxAuthorize'
                },
                async getUser(){
                    const qs = Qs.parse(window.location.search.substr(1))
                    const openid= qs.openid
                    const res = await axios.get('/getUser', {params:{
                            openid
                        }
                    })
                    console.log('res',res)
                }
            },
            mounted: function () {}});</script>
</body>

</html>
Copy the code

Global ticket (same with mongoose, modified from last time) Mongoose.js:

const mongoose = require('mongoose')
const {
    Schema
} = mongoose
mongoose.connect('mongodb://localhost:27017/weixin', {
    useNewUrlParser: true
}, () = > {
    console.log('Mongodb connected.. ')})exports.ServerToken = mongoose.model('ServerToken', {
    accessToken: String
});

// The following is added for seed_UP

schema = new Schema({
    access_token: String.expires_in: Number.refresh_token: String.openid: String.scope: String.create_at: String
});
// Customize the getToken method
schema.statics.getToken = async function (openid) {
    return await this.findOne({
        openid: openid
    });
};
schema.statics.setToken = async function (openid, token) {
    // If yes, update; if no, add
    const query = {
        openid: openid
    };
    const options = {
        upsert: true
    };
    return await this.updateOne(query, token, options);
};

exports.ClientToken = mongoose.model('ClientToken', schema);
Copy the code

Continue to change index.js:

const { ServerToken,ClientToken } = require('./mongoose')// Global ticket source
const oauth = new OAuth(conf.appid, conf.appsecret,
    async function (openid) {
        return await ClientToken.getToken(openid)
    },
    async function (openid, token) {
        return await ClientToken.setToken(openid, token)
    }
)
Copy the code

Write it out like this: perfect

8. Call wechat JSSDK

Preparation:

1. Obtain jsconfig

Index.html:

<cube-button @click='getJSConfig'> get jsconfig < / cube - button >async getJSConfig(){
  console.log('wx',wx)
  const res = await axios.get('/getJSConfig', {params: {url:window.location.href
      }
  })
  console.log('config',res)
  res.data.jsApiList = ['onMenuShareTimeline']
  wx.config(res.data)
  wx.ready(function () {
      console.log('wx.ready...... ')})}Copy the code

Index. Js:

/**
 * 获取JSConfig
 */
router.get('/getJsConfig'.async ctx => {
    console.log('getJSSDK... ',ctx.query)
    const res = await api.getJsConfig(ctx.query)
    ctx.body = res
})
Copy the code

If you get to wx.ready(), you can use the API for other functions at this time.

2. Obtain the network status

Wx.ready () is followed by wx.ready(), which of course makes the most sense:

// Get the network status
wx.getNetworkType({
     success: function (res) {
         // Return network type 2g, 3G, 4G, wifi
         const networkType = res.networkType
         console.log('getNetworkType... ', networkType)
     }
})
Copy the code

Access to my wifi environment, very perfect! The same goes for the rest of the JSSDK call methods!

One more thing, we usually have ten development projects with front and back end separation, so I changed the project to front and back end separation.

Development of front and rear end separation

1. Create a new weixin_pro project; 2. Copy the package.json of weixin project to weixin_proInstall dependency under weixin_pro: back-end dependency 6. Install dependency under Cube-UI: front-end dependency 7. Start front-end and back-end code respectively

The running effect is as follows:

X. Code address

The code before the front and back end separation: gitee.com/huqinggui/w… The code after the separation of the front and back ends: gitee.com/huqinggui/w…

🔥 🔥

Communication: