uniCloud
uniCloud腾讯云服务空间出现“access token disabled for ANONYMOUS login”错误提示的公告
尊敬的uniCloud开发者,您好!
uniCloud腾讯云服务空间于2024年12月升级了相关SDK,此次升级影响2024年12月10日后新创建的腾讯云空间,如果您在调试时碰到access token disabled for ANONYMOUS login相关错误,请升级HBuilderX到4.41 alpha版,感谢您的理解与支持。
2024年12月16日补充
部分开发者反馈升级到HBuilderX 4.41后仍有问题,请确认项目vue版本是否为vue2,针对这种情况可使用手动升级的临时方案来处理:
下载附件中的index.js.zip文件,解压后可以拿到index.js文件 在HBuilderX的安装目录下找到plugins/uniapp-cli/node_modules/@dcloudio/vue-cli-plugin-uni/packages/uni-cloud/dist/目录,将上述index.js拷贝到该目录替换原文件 重启HBuilderX后重新运行及编译打包很快会发布4.42版本修复vue2下腾讯云新创建空间的问题。
2024年12月19日补充
HBuilderX4.42 alpha版本已经发布,下载该版本无需手动替换HBuilderX文件。
Q&A
Q:小程序发行后无法正常运行
A:新版腾讯云服务空间的request合法域名有新增,除了之前的tcb-api.tencentcloudapi.com之外,还需要新增{spaceId}.ap-shanghai.tcb-api.tencentcloudapi.com域名({spaceId}替换为腾讯云的服务空间Id)
Q:抖音小程序报错Unauthenticated access is denied
A:报错的网络请求header中携带了头条的referer,也就是前端发起请求跨域了,需要在服务空间添加跨域域名,默认是tmaservice.developer.toutiao.com
参考文档:小程序中使用uniCloud
继续阅读 »
尊敬的uniCloud开发者,您好!
uniCloud腾讯云服务空间于2024年12月升级了相关SDK,此次升级影响2024年12月10日后新创建的腾讯云空间,如果您在调试时碰到access token disabled for ANONYMOUS login相关错误,请升级HBuilderX到4.41 alpha版,感谢您的理解与支持。
2024年12月16日补充
部分开发者反馈升级到HBuilderX 4.41后仍有问题,请确认项目vue版本是否为vue2,针对这种情况可使用手动升级的临时方案来处理:
下载附件中的index.js.zip文件,解压后可以拿到index.js文件 在HBuilderX的安装目录下找到plugins/uniapp-cli/node_modules/@dcloudio/vue-cli-plugin-uni/packages/uni-cloud/dist/目录,将上述index.js拷贝到该目录替换原文件 重启HBuilderX后重新运行及编译打包很快会发布4.42版本修复vue2下腾讯云新创建空间的问题。
2024年12月19日补充
HBuilderX4.42 alpha版本已经发布,下载该版本无需手动替换HBuilderX文件。
Q&A
Q:小程序发行后无法正常运行
A:新版腾讯云服务空间的request合法域名有新增,除了之前的tcb-api.tencentcloudapi.com之外,还需要新增{spaceId}.ap-shanghai.tcb-api.tencentcloudapi.com域名({spaceId}替换为腾讯云的服务空间Id)
Q:抖音小程序报错Unauthenticated access is denied
A:报错的网络请求header中携带了头条的referer,也就是前端发起请求跨域了,需要在服务空间添加跨域域名,默认是tmaservice.developer.toutiao.com
参考文档:小程序中使用uniCloud
收起阅读 »
quill-delta-converter 公共模块不存在,请在 uniCloud/database 目录右击“配置schema扩展公共模块“添加 quill-delta-converter 模块
问题描述1
在uni-admin项目中,导入uni-cms运行,通常就会出现如下报错,quill-delta-converter 公共模块不存在,请在 uniCloud/database 目录右击"配置schema扩展公共模块"添加 quill-delta-converter 模块。
解决办法1
只需要按照上面的方法,在uniCloud目录下找到database目录,右击添加 quill-delta-converter 模块即可解决
可以看一下database目录下面创建了一个新文件package.json,代码如下所示,就说明已经关联好了,可以简单看一下即可
{ "name": "database", "dependencies": { "quill-delta-converter": "file:../../uni_modules/uni-cms/uniCloud/cloudfunctions/common/quill-delta-converter" }, "extensions": {} }
通常来讲,这样操作完成之后,再刷新项目,之前的报错将不会存在,保险起见,可以重新启动一下项目,即可解决第一个问题。
问题描述2
在“本地云函数”调试uniadmin以及uni-cms,完全正常,没有问题,上线之前,将cloudfunction以及database全部上传到云端,然后在本地“连接云端云函数”,发现上面的问题再次出现,用户端项目使用的是uni-cms-article,也报同样的错误,明明我们已经安装第一种方法配置schema扩展公共模块quill-delta-converter,那为什么还报错那?
解决办法2
上传到云端,不单单是将cloudfunctions和database全部上传,如果你在database关联了公共模块或者扩展库,那么就需要“上传Schema扩展Js的配置”,这个很关键,这个过程其实相当于你的npm i安装一样,只有配置项,没有安装依赖,那云端肯定是不行的。
总结
我做项目出现这个问题的时候,花了好久的时间才看报错知道的这个问题,在这里记录一下,如果你也遇到了这个问题,帮你解决了,请给点赞支持一下哦,我是咸虾米_感谢大家。
继续阅读 »
问题描述1
在uni-admin项目中,导入uni-cms运行,通常就会出现如下报错,quill-delta-converter 公共模块不存在,请在 uniCloud/database 目录右击"配置schema扩展公共模块"添加 quill-delta-converter 模块。
解决办法1
只需要按照上面的方法,在uniCloud目录下找到database目录,右击添加 quill-delta-converter 模块即可解决
可以看一下database目录下面创建了一个新文件package.json,代码如下所示,就说明已经关联好了,可以简单看一下即可
{ "name": "database", "dependencies": { "quill-delta-converter": "file:../../uni_modules/uni-cms/uniCloud/cloudfunctions/common/quill-delta-converter" }, "extensions": {} }
通常来讲,这样操作完成之后,再刷新项目,之前的报错将不会存在,保险起见,可以重新启动一下项目,即可解决第一个问题。
问题描述2
在“本地云函数”调试uniadmin以及uni-cms,完全正常,没有问题,上线之前,将cloudfunction以及database全部上传到云端,然后在本地“连接云端云函数”,发现上面的问题再次出现,用户端项目使用的是uni-cms-article,也报同样的错误,明明我们已经安装第一种方法配置schema扩展公共模块quill-delta-converter,那为什么还报错那?
解决办法2
上传到云端,不单单是将cloudfunctions和database全部上传,如果你在database关联了公共模块或者扩展库,那么就需要“上传Schema扩展Js的配置”,这个很关键,这个过程其实相当于你的npm i安装一样,只有配置项,没有安装依赖,那云端肯定是不行的。
总结
我做项目出现这个问题的时候,花了好久的时间才看报错知道的这个问题,在这里记录一下,如果你也遇到了这个问题,帮你解决了,请给点赞支持一下哦,我是咸虾米_感谢大家。
收起阅读 »
分享一个第三方unicloud省市区数据库,顺便反馈一个bug
github地址 https://github.com/6613974/unicloud-china-city
==============================================
bug反馈, 客户端云数据库查询不支持地理查询(所有操作)均为==右侧值错误
示例代码需要在云函数内执行查询。
地图收费贵,uni自带的数据库个人不适应,重新整理了这个数据。 不需要基于经纬度的地理查询可以删除字段极大减小数据空间占用。
姑且算是满足了县级的地理逆解析,用小程序的可以用免费的经纬度接口配合查询。
==============================================
unicloud-china-city-geo
适用于unicloud于mongodb的大陆地区省市区及轮廓数据(gcj02)
数据来源
高德地图抓取
创建表
使用hubildX在database目录下用city-china.schema.json创建表,用city-china.json创建索引,或直接在unicloud控制台手动创建并添加索引,mongodb下自行修改导入文件格式
字段说明
code 唯一ID,省为两位,市四位,县六位 如北京为11 北京市1101 北京市西城区 110102
parent_code 上级ID 省级为null
name 地区简称 如北京
fullname 地区全称 如北京市
path 地区完整路径,如 北京市 北京市 西城区
pinyin 地区名称拼音 如 beijing
type 地区类型 0 省 1市 2县
first_letter 地区拼音首字母大写 如B
geometry 轮廓数据
基于经纬度的省市区查询
// 请在云函数中执行查询,uni-app本地无法执行地理查询
// lat 经度值 浮点数类型
// lng 纬度值 浮点数类型
const {errCode, data} = await db.collection('city')
.where({
geometry: db.command.geoIntersects({
geometry: db.Geo.Point(lat, lng)
})
})
.field({
code:true,
parent_code:true,
name:true,
fullname:true,
type:true,
first_letter:true,
pinyin:true,
})
.get()
省市区查询
省市区保存时只需保存最后一及的数值,以北京市西城区为例,110102, 可在path字段获取完整的省市区名称,无需二次查询
有时需要通过code反查上级code, 如北京可提取前两位获取11,北京市提取前4位即1101,无需反复查询数据库。
要查所有的省可以通过parent_code为null进行查询
要查北京下所有的市可模糊查询code为11开头且type为1
要查北京市下所有的区可模糊查询code为1101开头且type为2
可通过拼音或首字母进行搜索
不需要地理位置时可删除geometry字段可极大建设数据库空间占用
备注
数据来自高德,仅包括中国大陆地区,港、澳、台缺少轮廓数据的值为null
继续阅读 »
github地址 https://github.com/6613974/unicloud-china-city
==============================================
bug反馈, 客户端云数据库查询不支持地理查询(所有操作)均为==右侧值错误
示例代码需要在云函数内执行查询。
地图收费贵,uni自带的数据库个人不适应,重新整理了这个数据。 不需要基于经纬度的地理查询可以删除字段极大减小数据空间占用。
姑且算是满足了县级的地理逆解析,用小程序的可以用免费的经纬度接口配合查询。
==============================================
unicloud-china-city-geo
适用于unicloud于mongodb的大陆地区省市区及轮廓数据(gcj02)
数据来源
高德地图抓取
创建表
使用hubildX在database目录下用city-china.schema.json创建表,用city-china.json创建索引,或直接在unicloud控制台手动创建并添加索引,mongodb下自行修改导入文件格式
字段说明
code 唯一ID,省为两位,市四位,县六位 如北京为11 北京市1101 北京市西城区 110102
parent_code 上级ID 省级为null
name 地区简称 如北京
fullname 地区全称 如北京市
path 地区完整路径,如 北京市 北京市 西城区
pinyin 地区名称拼音 如 beijing
type 地区类型 0 省 1市 2县
first_letter 地区拼音首字母大写 如B
geometry 轮廓数据
基于经纬度的省市区查询
// 请在云函数中执行查询,uni-app本地无法执行地理查询
// lat 经度值 浮点数类型
// lng 纬度值 浮点数类型
const {errCode, data} = await db.collection('city')
.where({
geometry: db.command.geoIntersects({
geometry: db.Geo.Point(lat, lng)
})
})
.field({
code:true,
parent_code:true,
name:true,
fullname:true,
type:true,
first_letter:true,
pinyin:true,
})
.get()
省市区查询
省市区保存时只需保存最后一及的数值,以北京市西城区为例,110102, 可在path字段获取完整的省市区名称,无需二次查询
有时需要通过code反查上级code, 如北京可提取前两位获取11,北京市提取前4位即1101,无需反复查询数据库。
要查所有的省可以通过parent_code为null进行查询
要查北京下所有的市可模糊查询code为11开头且type为1
要查北京市下所有的区可模糊查询code为1101开头且type为2
可通过拼音或首字母进行搜索
不需要地理位置时可删除geometry字段可极大建设数据库空间占用
备注
数据来自高德,仅包括中国大陆地区,港、澳、台缺少轮廓数据的值为null
收起阅读 »
前言
官方已抹平了三个云厂商的绝大部分差异,但是还有部分功能表现不一致,或语法不统一等。
此表格汇总目前已知差异,旨在为开发者提供参考,无论是在首次选择云厂商,还是后期切换厂商,都能做到心中有数。
群策群力
一个人的精力有限,欢迎每一位开发者在留言中补充更多差异项。
套餐区别及云资源限制差异
官方已整理汇总,点击查看官方文档
云函数/云对象差异
功能项 腾讯云 阿里云 支付宝云 详情 备注 云函数数量限制 149 99 499 - - 最大超时时间 30秒 120秒 180秒 - 如果超时时间不够用,可递归调用云函数 定时任务单次最大运行时间 15分钟 2小时 3小时 - - QPS 500-1w 1k 2k - - 云端安装node_modules ✅ ❌ ✅ - npm包不占用云函数体积 读取文件路径 相对路径、绝对路径 相对路径 相对路径 - - 云函数内访问其他服务空间 ✅ ❌ ✅ 查看 - 实例回收时间 30分钟 15分钟 60秒 - 实例回收后,下次访问会触发冷启动 单实例多并发 ❌ ✅ ✅ 查看 - node版本 node8.9.4(可改node12) node16(可改node12) node18(可改node16) 查看 腾讯云使用node12时,可配置return后是否继续执行 时区 UTC+0 UTC+0 UTC+8 - 本地运行时是电脑的时区 WebSocket ❌ ❌ ✅ - 客户端需使用uni-app x IP防刷 基于Redis 基于Redis 网关层面 - - - - - - - -云数据库差异
功能项 腾讯云 阿里云 支付宝云 详情 备注 集合数量限制 300 100 400 - - _id区别 32位的字符串类型 24位的ObjectId类型 24位的字符串类型 查看 -前端网页托管差异
功能项 腾讯云 阿里云 支付宝云 详情 备注 history模式 ✅ ✅ ❌ 查看 - gzip压缩 ❓ ✅ ❌ 查看 - 防盗链 ✅ ❌ ✅ 查看 -继续阅读 »
前言
官方已抹平了三个云厂商的绝大部分差异,但是还有部分功能表现不一致,或语法不统一等。
此表格汇总目前已知差异,旨在为开发者提供参考,无论是在首次选择云厂商,还是后期切换厂商,都能做到心中有数。
群策群力
一个人的精力有限,欢迎每一位开发者在留言中补充更多差异项。
套餐区别及云资源限制差异
官方已整理汇总,点击查看官方文档
云函数/云对象差异
功能项 腾讯云 阿里云 支付宝云 详情 备注 云函数数量限制 149 99 499 - - 最大超时时间 30秒 120秒 180秒 - 如果超时时间不够用,可递归调用云函数 定时任务单次最大运行时间 15分钟 2小时 3小时 - - QPS 500-1w 1k 2k - - 云端安装node_modules ✅ ❌ ✅ - npm包不占用云函数体积 读取文件路径 相对路径、绝对路径 相对路径 相对路径 - - 云函数内访问其他服务空间 ✅ ❌ ✅ 查看 - 实例回收时间 30分钟 15分钟 60秒 - 实例回收后,下次访问会触发冷启动 单实例多并发 ❌ ✅ ✅ 查看 - node版本 node8.9.4(可改node12) node16(可改node12) node18(可改node16) 查看 腾讯云使用node12时,可配置return后是否继续执行 时区 UTC+0 UTC+0 UTC+8 - 本地运行时是电脑的时区 WebSocket ❌ ❌ ✅ - 客户端需使用uni-app x IP防刷 基于Redis 基于Redis 网关层面 - - - - - - - -云数据库差异
功能项 腾讯云 阿里云 支付宝云 详情 备注 集合数量限制 300 100 400 - - _id区别 32位的字符串类型 24位的ObjectId类型 24位的字符串类型 查看 -前端网页托管差异
功能项 腾讯云 阿里云 支付宝云 详情 备注 history模式 ✅ ✅ ❌ 查看 - gzip压缩 ❓ ✅ ❌ 查看 - 防盗链 ✅ ❌ ✅ 查看 -收起阅读 »
短信充值开放接口,APP一键登录充值开放接口等
希望官方可以出一个关于查询当前unicloud账号下云短信账号余额,以及模版列表,签名列表,申请签名,申请短信模板,以及充值短信账号条数、APP一键登录余额查询,余额充值等的功能的接口
这样就可以在自己的项目的管理后台进行操作,申请短信模板,签名,充值余额啥的,这样方便交给客户之后 不懂技术的客户 好操作
其他模块最好也能出一下相关接口
就像微信开放文档这样
继续阅读 »
希望官方可以出一个关于查询当前unicloud账号下云短信账号余额,以及模版列表,签名列表,申请签名,申请短信模板,以及充值短信账号条数、APP一键登录余额查询,余额充值等的功能的接口
这样就可以在自己的项目的管理后台进行操作,申请短信模板,签名,充值余额啥的,这样方便交给客户之后 不懂技术的客户 好操作
其他模块最好也能出一下相关接口
就像微信开放文档这样
收起阅读 »
【经验分享】【微信小程序】简单在已有账号系统基础上引入uni-id使用clientDB的权限管理
折腾了一下午,终于给我的小程序成功引入了uni-id,之前每次想到要迁移就头大,今天终于下定决心换到clientDB了,也是为了减少云函数的用量。在这里就简单分享一下校验。
参考:https://en.uniapp.dcloud.io/uniCloud/uni-id.html(这个教程是老的uni-id,对我够用了,不想迁移到新版)
安装uni-id
导入插件。 写config-center的配置,复制上面教程的文件只需要改mp-weixin.oauth.weixin内的appid和secret。 创建uni-id-users和opendb-verify-codes表,后者用于验证码对小程序其实不必要,但我不知道删了能不能跑。以上几步可以简单的安装好uni-id,然后便是迁移工作了。
迁移
首先我希望我的权限是依赖于openid的,所以我便利了我自己搭建的账号数据库,并逐条写入uni-id-user表,只需要写两个字段_id和wx_openid.mp-weixin,这两个字段同时设置为原先的openid。
登录
之后按照文档的微信登录段,新建一个云函数,内容如下
const uniID = require("uni-id"); exports.main = async function (event, context) { // const res = await uniID.loginByWeixin(event.code) const res = await uniID.loginByWeixin({ code: event.code, }); return res; };
注意这个云函数要选择公共依赖uni-id,安装的uni-id也需要选择公共依赖uni-open-bridge-common(我不知道为什么默认没选)。
以上是官方文档的,我将其修改为了
'use strict'; const uniID = require('uni-id'); const db = uniCloud.database(); const dbUID = db.collection('uni-id-users'); exports.main = async function (event) { const res = await uniID.loginByWeixin({ code: event.code }); if (res.uid !== res.openid) { await dbUID.doc(res.openid).set((await dbUID.doc(res.uid).field({ _id: false }).get()).data[0]); await dbUID.doc(res.uid).remove(); res.uid = res.openid; res.tokenExpired = 0; } return res; };
因为默认第一次登录的账户他会新建一条记录,而这条记录的uid不是原有的openid,所以需要手动修改。
同时修改以后原先的token是作废的,所以使用tokenExpired=0来让客户端手动重新二次调用。(每次都需要上传一个只能用一次的code)
然后我客户端用这个云函数取代了我原先用于获取openid的云函数,因为这个也会返回openid,正好还能登录一举两得。
角色
另一方面为了用上uni-id的角色系统,我还在我自己的关于权限变更的云函数里同时变更uni-id-users表的role字段,这样clientDB也可以用角色控制了xd
继续阅读 »
折腾了一下午,终于给我的小程序成功引入了uni-id,之前每次想到要迁移就头大,今天终于下定决心换到clientDB了,也是为了减少云函数的用量。在这里就简单分享一下校验。
参考:https://en.uniapp.dcloud.io/uniCloud/uni-id.html(这个教程是老的uni-id,对我够用了,不想迁移到新版)
安装uni-id
导入插件。 写config-center的配置,复制上面教程的文件只需要改mp-weixin.oauth.weixin内的appid和secret。 创建uni-id-users和opendb-verify-codes表,后者用于验证码对小程序其实不必要,但我不知道删了能不能跑。以上几步可以简单的安装好uni-id,然后便是迁移工作了。
迁移
首先我希望我的权限是依赖于openid的,所以我便利了我自己搭建的账号数据库,并逐条写入uni-id-user表,只需要写两个字段_id和wx_openid.mp-weixin,这两个字段同时设置为原先的openid。
登录
之后按照文档的微信登录段,新建一个云函数,内容如下
const uniID = require("uni-id"); exports.main = async function (event, context) { // const res = await uniID.loginByWeixin(event.code) const res = await uniID.loginByWeixin({ code: event.code, }); return res; };
注意这个云函数要选择公共依赖uni-id,安装的uni-id也需要选择公共依赖uni-open-bridge-common(我不知道为什么默认没选)。
以上是官方文档的,我将其修改为了
'use strict'; const uniID = require('uni-id'); const db = uniCloud.database(); const dbUID = db.collection('uni-id-users'); exports.main = async function (event) { const res = await uniID.loginByWeixin({ code: event.code }); if (res.uid !== res.openid) { await dbUID.doc(res.openid).set((await dbUID.doc(res.uid).field({ _id: false }).get()).data[0]); await dbUID.doc(res.uid).remove(); res.uid = res.openid; res.tokenExpired = 0; } return res; };
因为默认第一次登录的账户他会新建一条记录,而这条记录的uid不是原有的openid,所以需要手动修改。
同时修改以后原先的token是作废的,所以使用tokenExpired=0来让客户端手动重新二次调用。(每次都需要上传一个只能用一次的code)
然后我客户端用这个云函数取代了我原先用于获取openid的云函数,因为这个也会返回openid,正好还能登录一举两得。
角色
另一方面为了用上uni-id的角色系统,我还在我自己的关于权限变更的云函数里同时变更uni-id-users表的role字段,这样clientDB也可以用角色控制了xd
收起阅读 »
uniCloud 短信服务1001报错问题
阿里云短信函数设置了定时触发,会有1001的报错,报错信息是smsKey不能为空,官方文档也标注了更新至最新后不需要填写smsKey,解决办法是在HBuilder X里,选中短信发送函数,右击后选中管理公共模块或扩展库依赖,然后勾选上uni-cloud-sms并确定即可
继续阅读 »
阿里云短信函数设置了定时触发,会有1001的报错,报错信息是smsKey不能为空,官方文档也标注了更新至最新后不需要填写smsKey,解决办法是在HBuilder X里,选中短信发送函数,右击后选中管理公共模块或扩展库依赖,然后勾选上uni-cloud-sms并确定即可
收起阅读 »
关于uni手机号一键登录价格调整的公告
因三大运营商的集体涨价,自2024年10月01日零时起,uni手机号一键登录服务的价格将进行调整。
这是一次全行业涨价,其他如阿里云一键登陆等也都涨价了。
调整后的价格如下所示:
按量计费
按量价格为:0.03元/次
资源包
规格(次数) 价格(元) 相对按量计费单价(元/次) 1万 290 0.029 2万 570 0.0285 5万 1400 0.028 10万 2750 0.0275 20万 5400 0.027 50万 13250 0.0265 100万 26000 0.026 200万 51000 0.0255 500万 125000 0.025注意:资源包自购买之日起6个月内有效。
调价后,uni一键登录依然比其他云厂商的竞品便宜
阿里云阿里云的号码验证(一键登录)按量计费起步定价为4分/次,比uni一键登录的3分/次贵了33%;
阿里云一键登录需月消耗需超过500万次后,才可达到3分/次的单价,实际上大多开发者的App,月消耗是远到不了500万次的,详见阿里云 - 号码认证 - 产品计费
阿里云的套餐包,单价也比uni一键登录要贵很多,以阿里云官网单价最低的100万次套餐为例:
100万次的一键登录套餐,阿里云比uni一键登录要贵6500元:
厂商 价格(元) 单价(元/次) 阿里云 32500 0.0325 uni一键登录 26000 0.026实际上,阿里云100万次的套餐包,甚至比uni一键登录的按量计费还要贵不少。
腾讯云腾讯云的号码验证(一键登录)不支持在线自助开通,需要先填写申请表单,等待审核,且腾讯云仅支持按量计费,不支持资源包。
腾讯云的按量定价和阿里云一样,也是4分/次起步,同样比uni一键登录要贵33%;
详见:腾讯云号码认证 - 计费概述
即便加上uniCloud云函数的费用,uni一键登陆也更便宜。详见
总体而言,不管是按量计费,还是套餐包,uni一键登录都对中小开发者更为友好!
调价后,uni一键登录依然比短信更具性价比
uni一键登录相比短信验证码,具备明显的优势:
用户体验好:一键登录,无需等待和复制短信验证码,能有效降低用户流失率,提升用户注册转换率; 便宜:虽然调价了,但uni一键登录,平均每次验证仅需2分多,比短信验证码更为便宜; 安全:采用运营商网关认证,避免短信劫持,有效提升安全性相对短信验证码,我们更推荐开发者使用一键登录。
继续阅读 »
因三大运营商的集体涨价,自2024年10月01日零时起,uni手机号一键登录服务的价格将进行调整。
这是一次全行业涨价,其他如阿里云一键登陆等也都涨价了。
调整后的价格如下所示:
按量计费
按量价格为:0.03元/次
资源包
规格(次数) 价格(元) 相对按量计费单价(元/次) 1万 290 0.029 2万 570 0.0285 5万 1400 0.028 10万 2750 0.0275 20万 5400 0.027 50万 13250 0.0265 100万 26000 0.026 200万 51000 0.0255 500万 125000 0.025注意:资源包自购买之日起6个月内有效。
调价后,uni一键登录依然比其他云厂商的竞品便宜
阿里云阿里云的号码验证(一键登录)按量计费起步定价为4分/次,比uni一键登录的3分/次贵了33%;
阿里云一键登录需月消耗需超过500万次后,才可达到3分/次的单价,实际上大多开发者的App,月消耗是远到不了500万次的,详见阿里云 - 号码认证 - 产品计费
阿里云的套餐包,单价也比uni一键登录要贵很多,以阿里云官网单价最低的100万次套餐为例:
100万次的一键登录套餐,阿里云比uni一键登录要贵6500元:
厂商 价格(元) 单价(元/次) 阿里云 32500 0.0325 uni一键登录 26000 0.026实际上,阿里云100万次的套餐包,甚至比uni一键登录的按量计费还要贵不少。
腾讯云腾讯云的号码验证(一键登录)不支持在线自助开通,需要先填写申请表单,等待审核,且腾讯云仅支持按量计费,不支持资源包。
腾讯云的按量定价和阿里云一样,也是4分/次起步,同样比uni一键登录要贵33%;
详见:腾讯云号码认证 - 计费概述
即便加上uniCloud云函数的费用,uni一键登陆也更便宜。详见
总体而言,不管是按量计费,还是套餐包,uni一键登录都对中小开发者更为友好!
调价后,uni一键登录依然比短信更具性价比
uni一键登录相比短信验证码,具备明显的优势:
用户体验好:一键登录,无需等待和复制短信验证码,能有效降低用户流失率,提升用户注册转换率; 便宜:虽然调价了,但uni一键登录,平均每次验证仅需2分多,比短信验证码更为便宜; 安全:采用运营商网关认证,避免短信劫持,有效提升安全性相对短信验证码,我们更推荐开发者使用一键登录。
收起阅读 »
uniCloud 外部系统联登 注册功能 C# 完整示例
APP端
this.$http .post(`/uniCloudRegister`, { clientInfo:JSON.stringify(uni.getSystemInfoSync()) }) .then(res =>{ uni.stopPullDownRefresh() uni.hideNavigationBarLoading() console.info(res) }).catch(err => { console.error(err) uni.stopPullDownRefresh() uni.hideNavigationBarLoading() })
后台接口 UserController:ApiController
ConstantsConstants//业务系统登录后才需要联登到 uniCloud,所以不需要在注册时执行,而是单独给出了注册功能的接口 [HttpPost] [Route("uniCloudRegister")] public async Task<HttpResponseMessage> uniCloudRegister([FromBody] UniClient client) { HttpResponseMessage response = null; try { //此为验证当前系统token并转为 user类的工具,这里就不给出详细示例了 var ui = JwtHelper.AnalysisToken(HttpContext.Current.Request); //见 Utils string uniAppUserName = Utils.GetExternalUid(ui); string nonce = Utils.GetNonce(); // 获取当前时间戳(精确到毫秒) long timestamp = Utils.GetNowTimeStamp(); Dictionary<string, string> paramsDictionary = new Dictionary<string, string> { { "externalUid", uniAppUserName}, { "nickname", ui.Name}, }; //签名算法见 Utils string signature = Utils.GetSignature(paramsDictionary, nonce, timestamp); //client.clientInfo 为JSON.stringify(uni.getSystemInfoSync()) 这里再转回json对象 var cliInfo = JsonConvert.DeserializeObject<JObject>(client.clientInfo); Dictionary<string, object> param = new Dictionary<string, object>(); param.Add("clientInfo", cliInfo); param.Add("uniIdToken", ""); param.Add("params", paramsDictionary); // 将对象序列化为JSON字符串 string jsonContent = JsonConvert.SerializeObject(param); Dictionary<string, string> headers = new Dictionary<string, string>() { {"uni-id-nonce",nonce }, {"uni-id-timestamp",timestamp + ""}, {"uni-id-signature",signature} }; var res = await HttpHelper.SendPostAsync(Constants.PushRegister, jsonContent, headers); if (res.Count > 0) { response = Request.CreateResponse(System.Net.HttpStatusCode.OK, res); } else { response = Request.CreateResponse(System.Net.HttpStatusCode.BadRequest, "error"); } } catch (Exception ex) { response = Request.CreateErrorResponse(System.Net.HttpStatusCode.InternalServerError, "error"); } return response; }
Constants
//uniapp 外部系统联登 https://doc.dcloud.net.cn/uniCloud/uni-id/cloud-object.html#external public static readonly string PushUrl = "you url"; //uniapp 注册 public static readonly string PushRegister = PushUrl + "externalRegister"; //uniapp 登录 public static readonly string PushLogin = PushUrl + "externalLogin"; //uniapp 修改信息 public static readonly string PushUpdateUser = PushUrl + "updateUserInfoByExternal ";
UniClient
public class UniClient { public string clientInfo { get; set; } public string uniIdToken { get; set; } }
Utils
/// <summary> /// 根据用户信息 获取uniapp的uid, 这个就根据自己的业务来处理 /// </summary> /// <param name="ui"></param> /// <returns></returns> public static string GetExternalUid(UserInfo ui) { //分别为角色ID、 用户ID和用户账号 return ui.Role + "_" + ui.Id + "_" + ui.userName; } //获取随机字符串 这里其实可以固定返回一组字符串 public static string GetNonce() { return GenerateRandomStringLinq(8); } private static string GenerateRandomStringLinq(int length) { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; Random random = new Random(); return new string(Enumerable.Repeat(chars, length) .Select(s => s[random.Next(s.Length)]).ToArray()); } /// <summary> /// uniapp 鉴权签名算法 /// </summary> /// <param name="parameters"></param> /// <param name="nonce"></param> /// <param name="timestamp"></param> /// <returns></returns> public static string GetSignature(Dictionary<string, string> parameters, string nonce, long timestamp) { string paramsStr = GetParamsString(parameters); using (HMACSHA256 hmacSha256 = new HMACSHA256(Encoding.UTF8.GetBytes(Constants.RequestAuthSecret + nonce))) { string message = timestamp.ToString() + paramsStr; byte[] messageBytes = Encoding.UTF8.GetBytes(message); byte[] hashBytes = hmacSha256.ComputeHash(messageBytes); return ByteArrayToHexString(hashBytes).ToUpper(); } } /// <summary> /// 获取当前时间戳 单位毫秒 /// </summary> /// <returns></returns> public static long GetNowTimeStamp() { return (long)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds; } private static string GetParamsString(Dictionary<string, string> parameters) { var keys = new List<string>(parameters.Keys); keys.Sort(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < keys.Count; i++) { if (i != 0) { sb.Append("&"); } sb.Append(keys[i]).Append("=").Append(parameters[keys[i]]); } return sb.ToString(); } private static string ByteArrayToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); foreach (byte b in bytes) { string hex = b.ToString("x2"); sb.Append(hex); } return sb.ToString(); }
HttpHelper
/// <summary> /// POST异步请求 /// /// </summary> /// <param name="url">请求url</param> /// <param name="jsonContent"></param> /// <param name="headers"></param> /// <returns></returns> // 发送POST请求的函数 public static async Task<JObject> SendPostAsync(string url, string jsonContent, Dictionary<string, string> headers = null) { using (var client = new HttpClient()) { var jsonObject = new JObject(); if (headers != null) { foreach (KeyValuePair<string, string> header in headers) { client.DefaultRequestHeaders.Add(header.Key, header.Value); } } try { // 创建一个HttpContent对象,用于发送JSON数据 var httpContent = new StringContent(jsonContent, Encoding.UTF8, "application/json"); // 发送POST请求 HttpResponseMessage response = await client.PostAsync(url, httpContent); // 确保HTTP请求成功 //response.EnsureSuccessStatusCode(); // 读取响应内容 var responseBody = await response.Content.ReadAsStringAsync(); //LoggerHelper.Info("请求:" + url + ",参数:" + jsonContent + ",结果:" + responseBody); jsonObject = JsonConvert.DeserializeObject<JObject>(responseBody); } catch (HttpRequestException e) { LoggerHelper.Error("请求失败!",e); } return jsonObject; } }
tips: 出现了 "clientInfo.uniPlatform" is required. 是没有传参数clientInfo
参考 官方文档
适配URL化
外部系统联登
URL化请求鉴权签名
云端配置config.json的说明
继续阅读 »
APP端
this.$http .post(`/uniCloudRegister`, { clientInfo:JSON.stringify(uni.getSystemInfoSync()) }) .then(res =>{ uni.stopPullDownRefresh() uni.hideNavigationBarLoading() console.info(res) }).catch(err => { console.error(err) uni.stopPullDownRefresh() uni.hideNavigationBarLoading() })
后台接口 UserController:ApiController
ConstantsConstants//业务系统登录后才需要联登到 uniCloud,所以不需要在注册时执行,而是单独给出了注册功能的接口 [HttpPost] [Route("uniCloudRegister")] public async Task<HttpResponseMessage> uniCloudRegister([FromBody] UniClient client) { HttpResponseMessage response = null; try { //此为验证当前系统token并转为 user类的工具,这里就不给出详细示例了 var ui = JwtHelper.AnalysisToken(HttpContext.Current.Request); //见 Utils string uniAppUserName = Utils.GetExternalUid(ui); string nonce = Utils.GetNonce(); // 获取当前时间戳(精确到毫秒) long timestamp = Utils.GetNowTimeStamp(); Dictionary<string, string> paramsDictionary = new Dictionary<string, string> { { "externalUid", uniAppUserName}, { "nickname", ui.Name}, }; //签名算法见 Utils string signature = Utils.GetSignature(paramsDictionary, nonce, timestamp); //client.clientInfo 为JSON.stringify(uni.getSystemInfoSync()) 这里再转回json对象 var cliInfo = JsonConvert.DeserializeObject<JObject>(client.clientInfo); Dictionary<string, object> param = new Dictionary<string, object>(); param.Add("clientInfo", cliInfo); param.Add("uniIdToken", ""); param.Add("params", paramsDictionary); // 将对象序列化为JSON字符串 string jsonContent = JsonConvert.SerializeObject(param); Dictionary<string, string> headers = new Dictionary<string, string>() { {"uni-id-nonce",nonce }, {"uni-id-timestamp",timestamp + ""}, {"uni-id-signature",signature} }; var res = await HttpHelper.SendPostAsync(Constants.PushRegister, jsonContent, headers); if (res.Count > 0) { response = Request.CreateResponse(System.Net.HttpStatusCode.OK, res); } else { response = Request.CreateResponse(System.Net.HttpStatusCode.BadRequest, "error"); } } catch (Exception ex) { response = Request.CreateErrorResponse(System.Net.HttpStatusCode.InternalServerError, "error"); } return response; }
Constants
//uniapp 外部系统联登 https://doc.dcloud.net.cn/uniCloud/uni-id/cloud-object.html#external public static readonly string PushUrl = "you url"; //uniapp 注册 public static readonly string PushRegister = PushUrl + "externalRegister"; //uniapp 登录 public static readonly string PushLogin = PushUrl + "externalLogin"; //uniapp 修改信息 public static readonly string PushUpdateUser = PushUrl + "updateUserInfoByExternal ";
UniClient
public class UniClient { public string clientInfo { get; set; } public string uniIdToken { get; set; } }
Utils
/// <summary> /// 根据用户信息 获取uniapp的uid, 这个就根据自己的业务来处理 /// </summary> /// <param name="ui"></param> /// <returns></returns> public static string GetExternalUid(UserInfo ui) { //分别为角色ID、 用户ID和用户账号 return ui.Role + "_" + ui.Id + "_" + ui.userName; } //获取随机字符串 这里其实可以固定返回一组字符串 public static string GetNonce() { return GenerateRandomStringLinq(8); } private static string GenerateRandomStringLinq(int length) { const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnopqrstuvwxyz"; Random random = new Random(); return new string(Enumerable.Repeat(chars, length) .Select(s => s[random.Next(s.Length)]).ToArray()); } /// <summary> /// uniapp 鉴权签名算法 /// </summary> /// <param name="parameters"></param> /// <param name="nonce"></param> /// <param name="timestamp"></param> /// <returns></returns> public static string GetSignature(Dictionary<string, string> parameters, string nonce, long timestamp) { string paramsStr = GetParamsString(parameters); using (HMACSHA256 hmacSha256 = new HMACSHA256(Encoding.UTF8.GetBytes(Constants.RequestAuthSecret + nonce))) { string message = timestamp.ToString() + paramsStr; byte[] messageBytes = Encoding.UTF8.GetBytes(message); byte[] hashBytes = hmacSha256.ComputeHash(messageBytes); return ByteArrayToHexString(hashBytes).ToUpper(); } } /// <summary> /// 获取当前时间戳 单位毫秒 /// </summary> /// <returns></returns> public static long GetNowTimeStamp() { return (long)DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds; } private static string GetParamsString(Dictionary<string, string> parameters) { var keys = new List<string>(parameters.Keys); keys.Sort(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < keys.Count; i++) { if (i != 0) { sb.Append("&"); } sb.Append(keys[i]).Append("=").Append(parameters[keys[i]]); } return sb.ToString(); } private static string ByteArrayToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); foreach (byte b in bytes) { string hex = b.ToString("x2"); sb.Append(hex); } return sb.ToString(); }
HttpHelper
/// <summary> /// POST异步请求 /// /// </summary> /// <param name="url">请求url</param> /// <param name="jsonContent"></param> /// <param name="headers"></param> /// <returns></returns> // 发送POST请求的函数 public static async Task<JObject> SendPostAsync(string url, string jsonContent, Dictionary<string, string> headers = null) { using (var client = new HttpClient()) { var jsonObject = new JObject(); if (headers != null) { foreach (KeyValuePair<string, string> header in headers) { client.DefaultRequestHeaders.Add(header.Key, header.Value); } } try { // 创建一个HttpContent对象,用于发送JSON数据 var httpContent = new StringContent(jsonContent, Encoding.UTF8, "application/json"); // 发送POST请求 HttpResponseMessage response = await client.PostAsync(url, httpContent); // 确保HTTP请求成功 //response.EnsureSuccessStatusCode(); // 读取响应内容 var responseBody = await response.Content.ReadAsStringAsync(); //LoggerHelper.Info("请求:" + url + ",参数:" + jsonContent + ",结果:" + responseBody); jsonObject = JsonConvert.DeserializeObject<JObject>(responseBody); } catch (HttpRequestException e) { LoggerHelper.Error("请求失败!",e); } return jsonObject; } }
tips: 出现了 "clientInfo.uniPlatform" is required. 是没有传参数clientInfo
参考 官方文档
适配URL化
外部系统联登
URL化请求鉴权签名
云端配置config.json的说明
收起阅读 »
相关知识
十分钟,零基础使用uniCloud完成后端管理系统搭建一
不是吧,还有人不会做圣诞节头像小程序(可开通流量主,赚零花钱)
UniApp实现用户反馈与错误日志的采集与处理
10 个 GitHub 上超火和超好看的管理后台模版,又能愉快的上班摸鱼了
网址: uniCloud https://www.huajiangbk.com/newsview1293751.html
上一篇: 君子兰缺水症状.doc |
下一篇: 三种将iCloud照片导出的简单 |
推荐分享

- 1君子兰什么品种最名贵 十大名 4012
- 2世界上最名贵的10种兰花图片 3364
- 3花圈挽联怎么写? 3286
- 4迷信说家里不能放假花 家里摆 1878
- 5香山红叶什么时候红 1493
- 6花的意思,花的解释,花的拼音 1210
- 7教师节送什么花最合适 1167
- 8勿忘我花图片 1103
- 9橄榄枝的象征意义 1093
- 10洛阳的市花 1039