微信小程序开发——前端如何区分小程序运行环境
前言:
之前用vue做h5项目,对于接口请求,都是根据前端访问域名来判断运行环境,然后自动适配对应的服务器地址的。这样的好处就是在开发、测试及发布上线全程都不需要手动去改接口请求地址,只要提前配置好就行了。这样处理之后,只需要打包一次,就能同时适应所有环境而不需要再去改代码,打不同的包了。
对于微信小程序,发现前端并没有可以区分小程序运行环境(开发者工具、开发版、体验版及正式版)的API(真的没有),这就直接导致了开发的时候链接测试服务器就需要手动的去修改服务器地址了。最近找到一种解决方法,实现上虽然还是有点曲折,但是总算能解决问题了,也希望腾讯后边能开发这方面的API。
实现原理:

如图,小程序网络请求的请求头中的Reffer为固定格式:
Referer:https://servicewechat.com/小程序的appid/运行环境/page-frame.html
经验证,开发者工具中,为devtools,开发版及体验版为0,正式版则为1,这样就能区分运行环境了。
但是这个请求头通过前端并不能获取,所以只有让后端在第一个接口请求中获取referer,然后返回给前端就好了。
实现步骤:
1. 后端将接口访问请求头中的reffer返回给前端:
注:只需要在小程序第一个接口(必须访问)中将reffer返回给前端就好了,如果第一个接口不一定访问,那么可以让后端单独开放一个接口给前端来判断即可。
2. 前端对接口请求封装代码进行改造,如图:

代码解析:
贴下代码,加粗字体为修改部分:
/**
* 封装http请求方法,已实现根据访问环境自动匹配服务器环境,原理详见README.md
*/
var apiUrl = "https://xxx.xxx.cn"; //生产环境
var apiUrlDev = "http://xxx.xxx.cn"; //测试环境
//优先设置为缓存中的服务器地址
var storageApi = wx.getStorageSync("apiUrl")
if (storageApi) {
apiUrl = storageApi
}
//封装http方法给api.js直接使用
const http = (params) => {
//返回promise 对象
return new Promise((resolve, reject) => {
wx.request({
url: apiUrl + params.url,
data: params.data,
header: params.header || {
"Content-Type": "application/x-www-form-urlencoded",
"token": wx.getStorageSync("token")
},
method: params.method || 'POST',
dataType: params.dataType,
responseType: params.responseType,
success: function(res) {
//1. 根据小程序打开后第一个接口请求判断小程序访问环境
if (!wx.getStorageSync("apiUrl") && params.url == "/goods/img" && res.statusCode == 200 && res.data) {
//前端根据后端返回的reffer内容进行截取,获取判断环境的变量(后端在第一个约定的接口中将请求头中的reffer返回)
const version = res.data.reffer && res.data.reffer.split('/')[4]
if (!version || version == 0 || version == "devtools") {
//非正式环境(开发者环境,开发版、体验版),保存测试服务器地址到缓存,并设置为测试服务器,然后重调本接口
wx.setStorageSync("apiUrl", apiUrlDev)
apiUrl = apiUrlDev
//返回-1状态码给调用该接口的方法进行回调
resolve({
retCode: "-1"
})
}
} else {
//2. 非正式环境,所有接口访问都在控制台输出访问接口及响应数据,以便于调试
if (storageApi) console.log("api", params.url, '::', res) //3. 接口响应数据正常处理逻辑,仅在生产环境接口访问出错时,控制台输出接口及响应数据
if (res.statusCode == 200) {
if (res.data.retCode != "000000" && !storageApi) console.log("api", params.url, '::', res)
resolve(res.data)
} else {
wx.showToast({
title: "系统繁忙,请稍后再试~",
icon: "none"
})
if (!storageApi) console.log("api", params.url, '::', res)
}
}
},
fail: function(e) {
wx.showToast({
title: "系统繁忙,请稍后再试~",
icon: "none"
})
reject(e)
}
})
})
}
module.exports = {
http: http
}
如上,主要做了两个比较大的改动:
1.在服务器地址设置的逻辑中,默认为生产环境服务器地址,如果缓存中有apiUrl,则使用缓存中的地址:
var apiUrl = "https://xxx.xxxx.cn"; //生产环境服务器地址
var apiUrlDev = "http://xxx.xxxx.cn";//测试环境服务器地址
var storageApi = wx.getStorageSync("apiUrl")
//缓存中有服务器地址,则使用缓存中的服务器地址
if (storageApi) {
apiUrl = storageApi
}
2.在响应数据处理的逻辑中,如果缓存中没有保存服务器地址(apiUrl)且是指定的接口(小程序第一个必须访问且与后端约定返回请求头中的reffer给前端使用),则获取响应数据中的reffer,并截取reffer中的version字段:
if (!wx.getStorageSync("apiUrl") && params.url == "/goods/img" && res.statusCode == 200 && res.data) {
//缓存中无apiUrl且是第一个必须访问的接口,则获取reffer(与后端约定返回这个值)
var version = res.data.reffer && res.data.reffer.split('/')[4]
...
3.对reffer中的version进行判断,如果是0或“devtools”,则将测试服务器地址保存到缓存中,并返回-1给调用该接口的方法进行回调:
if (!version || version == 0 || version == "devtools") {
//非正式环境(开发者环境,开发版、体验版),保存测试服务器地址到缓存,并设置为测试服务器,然后重调本接口
wx.setStorageSync("apiUrl", apiUrlDev)
apiUrl = apiUrlDev
//返回-1状态码给调用该接口的方法进行回调
resolve({
retCode: "-1"
})
}
4. 页面业务逻辑代码部分也要做相应调整:
if (data.retCode == "-1"){
self.loadGood(goods_id)
return;
}
经过上边的改造,正式版小程序第一个接口访问中不符合 version == 0 || version == "devtools" 条件而不再执行条件判断后续代码,对当前接口数据处理及后续其他接口访问都无影响。之所以加了 !version 这个条件,是因为开发阶段,新增的这个字段还未同步到正式环境,所以做了这个兼容,即没有这个字段则直接访问测试环服务器。
对于测试环境,则在启动小程序的时候,访问第一个接口 "/goods/img" ,服务器返回reffer值可以判断出非正式环境,则将测试服务器地址保存到缓存中,并回调当前接口 http(params); ,这样就会重新调用当前接口,后续其他接口访问则直接访问测试服务器。
至此,代码改造完成,剩下的就是在不同环境中进行验证了。
注意事项:
1. 本方法只能算曲线救国,如果是非正式环境,则第一个请求接口会请求两次,第一次访问正式服务器,第二次访问测试服务器,其他就没多大影响了。可以直接让后端单独写一个接口来判断小程序运行环境,这样就不需要改动原有接口了。
2. 无论是采用第一个接口,还是单独写接口,都是需要先访问一次正式环境的,这个没办法,因为我们目前采用的是小程序网络请求的请求头来判断运行环境的。
3. 虽然不尽完美,但在目前的情况下,貌似也只能这样处理了,至少以后不用每次发布版本的时候再手动改服务器访问地址了。
后续:
2018.12.29
发现小程序提审的时候,腾讯是通过体验版进行审核验证的,所以如果要使用本文中对生产、非生产(开发、体验)环境进行区分的方法,测试服务器也需要支持https访问,并绑定到小程序管理后台的request域名中去。不然应该是审核不通过的了。
还有另外一种方法,就是复用代码包再创建一个测试用的小程序(无需申请小程序,仍使用原来的appid)进行开发调试,带开发环境验证没问题,再将代码合并到正式小程序代码中,这样测试小程序链接测试服务器,正式小程序项目链接生产环境,这样开发调试就不会影响到正式小程序的提审发布了。
微信小程序开发——前端如何区分小程序运行环境的更多相关文章
- 微信小程序开发教程 #043 - 在小程序开发中使用 npm
本文介绍了如何在微信小程序开发中使用 npm 中包的功能,大大提高微信小程序的开发效率,同时也是微信小程序系列教程的视频版更新. 微信小程序在发布之初没有对 npm 的支持功能,这也是目前很多前端开发 ...
- 微信小程序--关于加快小程序开发的几个小建议
加快小程序开发的几个小建议 1.使用 app.json创建页面 按照我们平常的开发习惯,创建一个新的页面,一般都会先创建文件夹,再创建对应page的形式,创建完成后,app.json中会自动注册该 ...
- Win32 程序开发:创建一个应用程序窗口
一.创建一个应用程序窗口 代码如下: // 头文件 #include <windows.h> // 全局变量 WCHAR g_lpszClassName[] = L"CLASSN ...
- vsCode怎么为一个前端项目配置ts的运行环境
vsCode为一个前端项目配置ts的运行环境,ts文件保存的时候自动编译成js文件: 假设此前端项目名称为Web:文件结构如图 1. 在根目录中新建一个“.vscode”文件夹,里面建一个“tasks ...
- 微信小程序开发公测,小程序账号申请办法攻略
11月3号晚上 10 点,微信公众平台发布公告,宣布微信小程序正式开放公测.此次小程序公测允许开发者将产品提交至微信公众平台审核,但是暂时不支持发布,也就是说普通消费者若想体验小程序,还需要等待一段时 ...
- 微信小程序开发——打开另一个小程序
微信小程序打开另一个小程序,有两种方法:1.超链接:2.点击按钮. 全局配置: 跳转到其他小程序,需要在当前小程序全局配置中配置需要跳转的小程序列表,代码如下: App.json { ... &quo ...
- 跟我一起,利用bitcms内容管理系统从0到1学习小程序开发:一、IIS下SSL环境搭建
缘起 1.从事互联网十来年了,一直想把自己的从事开发过程遇到的问题给写出来,分享给大家.可是可是这只是个种想法,想想之后就放下了,写出来的类文章是少之又少.古人说无志之人常立志,有志之人立长志.今天, ...
- docker 和 vagrant 作为程序发布 和 开发的独立而统一的运行环境
docker 和 vagrant 作为程序发布 和 开发的运行环境,可以提供打包程序,并使得程序运行在一个独立的虚拟环境中,避免程序发布到客户机之后,环境不一致导致的诸多问题. refer: ...
- 《Symfony 5全面开发》教程02、安装运行环境并初始化Symfony项目
Symfony是PHP框架,在学习Symfony之前,我们需要安装PHP运行环境.如果你是MacOS系统,可以使用Homebrew来安装PHP运行环境. Homebrew官网 https://brew ...
随机推荐
- Spring Cloud (3)B Ribbon 负载均衡 IRule
package com.service.config; import com.netflix.loadbalancer.IRule;import com.netflix.loadbalancer.Ra ...
- sql server 字符串字节长度
SQL Server 字符个数,字节长度,len不是你想要的字节数,datalength才能得到字节数 select len('娜娜123') ,datalength('娜娜123') 5 ...
- JEECG 3.7.3 新春版本发布,企业级JAVA快速开发平台
JEECG 3.7.3新春版本发布 - 微云快速开发平台 导读 ⊙精美Echart报表 ⊙二维码生成功能 ⊙Online接口改造采用JWT机制 ⊙智能菜单搜索 ⊙代码生成器模板优 ...
- mingw 设置python 设置git环境变量
1.python路径设置: 安装python 比如目录:C:\Python27 假如mingw安装C盘根目录下的话,进入下面目录:C:\MinGW\msys\1.0\etc 找到 fstab 文件修改 ...
- APP-4-百度地图定位
APP-3-百度地图应用 需要根据上一步完成百度地图应用的测试,本文介绍Hbuilder通过MUI框架完成百度地图的定位. 1.代码部分 <!DOCTYPE html> <html& ...
- Druid参考配置
pom中的maven dependency <dependency> <groupId>com.alibaba</groupId> ...
- XML中的变量传值
在action的java类中定义变量之后,在XML中获取该变量进行对应传值:: 在指定方法中获取XML配置文件的变量传值::
- category,extension区别
extension是在编译的时候就决定了的,跟普通的头文件是一样的,所以可以添加属性.实例变量.方法.并且添加extension的前提是你有这个类的源代码. category是在程序运行的时候才决定的 ...
- js 滑动门的实现
原理:滑动门,这里以图片进行实例,首先设定主盒子div的宽度和高度设定,并进行图片初始化位置的设定,然后将图片绑定事件,并设定要达到的效果 html代码: <!DOCTYPE html> ...
- 6.面向对象 -类.md
目录 1. static: 2. 类在内存中,每一个类在创建在栈内存中,当创建一个对象的时候,将非类变量再堆内存中创建,而类变量是不会因为创建对象而在堆中重新创建 3. 对象.引用和指针: 4. 类名 ...