在微信公众号开发中,必须要跟微信服务进行通讯、交互,包括但不限于如下内容:
开发的时候真的是Ri了Dog了,每次完成某些功能都需要将代码打包提交到线上测试,不仅繁琐,更是增加了调试的难度和精力!
针对以上问题,可以使用内网穿透,让公众号中绑定的域名最终指向我们开发环境本地。
通过搜索,发现natapp和sunny-ngrok这两款工具可以实现,具体请参考这篇博文,该博主已经很详细的介绍了这两款工具的使用方法。
本文我们介绍使用开源的内网穿透工具
fatedier/frp+Nginx,自己搭建一个内网穿透隧道,以达到我们的目的。

50110,并通过/mpServe接收微信公众号服务器发来的请求。test.666.com111.112.113.114test.666.com域名在公众号配置中设置服务器地址,并成功在本地开发环境中收到来自微信服务器发送的消息。test.666.com域名调用公众号开放的JS接口。test.666.com域名进行网页授权登录。test.666.com域名,可以访问到本地开发环境中的公众号网页应用,并且无需在本地打包,实时热更新。test.666.com作为代替。111.112.113.114。说明:
- 本文的开发环境和云服务器都是Windows,因此下载的工具都是Windows版本,各位请根据自己的开发环境、云服务器环境下载对应的工具版本。
- 本文使用的是阿里云的域名,非阿里云的域名控制台可能不一样,请各位根据自己的域名控制台,做相应的配置即可。
达成这亿个小目标,都需要配置什么,以及存在哪些问题需要解决?
test.666.com解析到云服务器公网IP:111.112.113.114。test.666.com后,将指向云服务器的80端口,frp服务端启用HTTP类型代理监听180端口,那么就需要使用Nginx,将域名为test.666.com的请求(80端口),转发到180端口。frp客户端收到来自frp服务端的数据,该如何处理:
test.666.com的请求,需要用Nginx转发到网页开发环境的端口:http://192.168.2.222:50101;
http://localhost:50101test.666.com/mpServe的请求,需要用Nginx转发到后端应用的端口:50110;JS接口安全域名、业务域名、网页授权域名为test.666.com时,微信会检测该域名根目录下,其指定的随机校验文本是否存在,但是我们test.666.com指向的是50101开发端口,那么就需要配置Nginx:收到来自test.666.com/MP_verify_****.txt的请求时,直接返回校验字符串。Invalid Host/Origin header该如何处理?关闭disableHostCheck配置即可。a. 打开服务端配置文件frps.ini

b. 配置如下:
[common]
# 服务端监听端口,接收 frpc 的连接,默认值:7000
bind_port = 7000
# 为 HTTP 类型代理监听的端口,启用后才支持 HTTP 类型的代理,未配置则默认不启用
vhost_http_port = 180
# 鉴权方式: token, oidc
authentication_method = token
# 鉴权使用的 token 值
token = token_123456789
# 启用 Dashboard 监听的本地地址
dashboard_addr = 0.0.0.0
# 启用 Dashboard 监听的本地端口
dashboard_port = 7500
# Dashboard 登录账号
dashboard_user = admin
# Dashboard 登录密码
dashboard_pwd = admin
c. 保存后将配置文件frps.ini,以及服务端可执行文件frps.exe 一并上传到云服务器。

d. 控制台运行命令:start frps -c frps.ini,启动成功后如下图所示:

e. 检查是否成功:云服务器中使用浏览器打开链接http://localhost:7500,成功打开登录页面即代表成功。(您也可以使用配置文件中设置的账号密码进行登录)

f.!!!注意!!!:云服务器安区组
入方向需要添加:端口7000以及端口180允许,如果需要外网访问Dashboard,还需要添加端口7500允许。
a. Nginx增加配置项,如下:
# 监听80端口的 test.666.com 域名请求,并转发到 180 端口
server {
listen 80; # 监听80端口
server_name test.666.com; # 监听的域名
location / {
# 设置header
proxy_redirect http://$host/ http://$http_host/;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
# 转发到180端口
proxy_pass http://127.0.0.1:180;
}
}
b. 保存配置后,控制台运行:nginx -s reload让Nginx重新加载配置。
a. 打开客户端配置文件frpc.ini

b. 配置如下:
[common]
# 连接服务端的地址
server_addr = 111.112.113.114
# 连接服务端的端口
server_port = 7000
# 鉴权方式:token, oidc,需要和服务端一致
authentication_method = token
# 鉴权使用的 token 值,需要和服务端一致
token = token_123456789
[web01]
type = http
local_ip = 127.0.0.1
local_port = 80
# 域名
custom_domains = test.666.com
c. 保存后配置文件后,在本地环境中控制台运行命令:start frpc -c frpc.ini,成功后如下图所示:

start nginxhttp://localhost/,成功后如下图所示:
进入域名控制台,添加一条A记录,指向云服务器公网IP即可,不同域名商的后台都不一样,请各位自行设置。
本文中设置如下:

根据每个服务商的时间,等待域名解析成功,本文中阿里云大概在10分钟左右。
浏览器打开网址http://test.666.com,如果成功穿透,即可正常展示本地环境搭建的Nginx服务,如下:

到这里,我们已经成功完成自己搭建一个支持HTTP协议的内网穿透隧道。
具体流程如下图:

看到这里,可能有人会提出疑问:
带着以上问题,我们继续完成目标,并且在本文最后给出解释。
本地开发环境中,本文的服务端程序,运行在50110端口,并通过/mpServe接收来自微信公众号服务的请求。
也就是说需要让微信公众号将请求发送到我们本地环境的http://localhost:50110/mpServe这个位置。
那通过前面的内网穿透,是不是让公众号将请求发送到http://test.666.com:50110/mpServe就行?
当然不可以,因为微信公众号配置服务器URL的时候不允许在链接中出现端口…Ri了Dog了 Again
那么我们就让本地环境中的Nginx 将/mpServe的数据转发到50110端口不就行了!
a. 本地环境中Nginx添加配置,如下:
server {
listen 80; # 监听的端口
server_name test.666.com; # 监听的域名
# 将80端口中收到来自 http://test.666.com/mpServe 的数据,转发到50110端口
location ^~/mpServe {
proxy_pass http://localhost:50110;
}
}
b. 保存配置后,命令行执行命令:nginx -s reload 让Nginx重新载入配置。
c. 在微信公众号中配置服务器URL,如图:

!!!注意!!!:本地环境中50110端口的公众号服务端,需要各位自己处理响应微信发送的Token验证噢,不然穿透是成功的,但是公众号不能验证Token,提交会提示失败!
到这里,我们已实现本地环境中的服务端能成功接收并回复微信公众的发来的消息请求。

这个图不陌生吧? 各位在配置公众号设置中JS接口安全域名、网页授权域名、业务域名保存的时候,微信服务器都会验证上图所述的内容。
这个问题很好解决,我们让Nginx在收到/MP_verify_xxxx.txt请求的时候,直接返回校验字符串不就好了,开始动手:
a. 下载文本MP_verify_xxxx.txt文本,打开查看文本中的字符串内容,文本中的字符串为:3wl6rZgobo3WEMaA,如图:

b.本地环境中Nginx添加配置,如下:
server {
listen 80; # 监听的端口
server_name test.666.com; # 监听的域名
# 将80端口中收到来自 http://test.666.com/mpServe 的数据,转发到50110端口
location ^~/mpServe {
proxy_pass http://localhost:50110;
}
# ======= 以下为新增的配置 =======
# 在80端口中收到 http://test.666.com/MP_verify_3wl6rZgobo3WEMaA.txt 请求时,直接返回字符串 '3wl6rZgobo3WEMaA'
location ~ ^/MP_verify_3wl6rZgobo3WEMaA.txt {
default_type text/html;
return 200 '3wl6rZgobo3WEMaA';
}
}
c.保存配置后,命令行执行命令:nginx -s reload 让Nginx重新载入配置。
d.公众号设置中提交JS接口安全域名、网页授权域名、业务域名设置即可。
成功后,我们就实现了可以在本地环境中调用JS接口、可以使用test.666.com进行网页授权登录等操作。
test.666.com域名时,可以访问到本地开发环境中的公众号网页应用,并且无需在本地打包,实时热更新:其实到这里,我们将本地的公众号网页应用打包后,放入Nginx中html目录,使用http://test.666.com域名就能成功运行本地的网页应用。
但是,咱的野心不止于此,凭什么每次更新代码后,还得打包一次?而且这也不好调试啊!
先看看本文中的网页开发环境:
本文中使用vue2.x开发公众号网页应用,npm run serve后,本地环境地址为:

看到这里,大家应该知道了吧,让Nginx将http://test.666.com的请求全部反向代理到50101端口不就好了,开始动手:
a. 本地环境中Nginx添加配置,如下:
server {
listen 80; # 监听的端口
server_name test.666.com; # 监听的域名
# 将80端口中收到来自 http://test.666.com/mpServe 的数据,转发到50110端口
location ^~/mpServe {
proxy_pass http://localhost:50110;
}
# 在80端口中收到 http://test.666.com/MP_verify_3wl6rZgobo3WEMaA.txt 请求时,直接返回字符串 '3wl6rZgobo3WEMaA'
location ~ ^/MP_verify_3wl6rZgobo3WEMaA.txt {
default_type text/html;
return 200 '3wl6rZgobo3WEMaA';
}
# ======= 以下为新增的配置 =======
# 将80端口中收到来自 http://test.666.com 的数据,转发到50101端口
location / {
proxy_pass http://192.168.2.222:50101; # 这里必须是 192.168.xxx.xxx,不可以是localhost
}
}
b.保存配置后,命令行执行命令:nginx -s reload 让Nginx重新载入配置。
c.打开微信开发者工具,打开链接http://test.666.com

搞定!
Invalid Host/Origin header使用http://test.666.com打开我们本地环境中的网页应用后,无论是微信开发者工具,还是浏览器,控制台都会循环输出错误Invalid Host/Origin header:

这是webpack本身出于安全考虑,检查header中的Host、Origin不一致,以为是受到攻击提示从错误信息。
咱这是内网穿透,当然会出现这个问题,所以,禁用掉disableHostCheck配置即可。
打开配置文件:

添加如下内容:
...
devServer: { // 在devServer配置中
...
disableHostCheck: true, // 新增该配置项
...
}
...
保存配置,重启npm:npm run serve
刷新微信开发者工具 或 浏览器
搞定,烦人的错误无了

到这我们已经完成全部目标,再也不用单独写代码检测开发环境和线上环境了,再也不用频繁打包上传到服务器了,再也不用在线上调试到抓狂了!!!
下面,来说说前面提到的疑问,为什么云服务器和本地环境中为什么不将Nginx这一层直接取消。
先看个图:

先说本地环境:
上图所述,本地环境中需要针对/mpServe、/、/MP_verify_xxx.txt 做出不同的转发,使用Nginx就没什么好说的了。
再说云服务器:
上图所述,如果服务器中运行了其他的应用,那么Nginx还是需要的。
如果服务器中没有其他应用,则完全可以将Nginx这层去掉,将frp服务端的端口配置为80即可。