今天发现在开发新项目时,微信分享失效了,开启 debug = true 后,在微信开发工具中提示:
{"errMsg":"updateTimelineShareData:fail, the permission value is offline verifying"}
在真机上提示:
{"errMsg":"config:ok"}
{"errMsg":"updateAppMessageShareData:ok"}
{"errMsg":"updateTimelineShareData"}
仍然找不出原因。
尝试打开已上线的项目,分享功能均正常。
偶然发现,当打开使用 JS-SDK 分享后的图文框的页面,能够正常分享,而直接点开链接的页面,没有分享按钮。
这难免不让人联想到最近GJ出的新政,新版微信已经开放淘宝、抖音等平台的链接打开权限,只是当点击链接的时候会出现一个风险提示页面:
而一旦由这个页面进入的网页,分享功能均不能正常。
另外还测试了以下几种情况的分享功能也能正常:
公众号推送的图文或链接、公众号菜单、个人发送到公众号的链接、通过扫一扫打开的页面等。
-- 2021.9
m① R②
x① R②
① 表示屏幕尺寸,一般有 15、17 等
② 表示第几代,对应 CPU 和显卡的不同,数字越大越新
相同 ① 与 ② 的情况下仍有细分款式,对应内存、硬盘、屏幕分辨率刷新率等不同
x 系列是全新的系列,是 m 系列的更新款(m 系列不再更新),相比 m 系列提升了散热性能
屏幕尺寸 | 型号 | 处理器 | 显卡 | 发布时间 |
14.0 英寸 | x14 R1 | 12 代 i7 | 30 系 | 2022年1月 |
15.6 英寸 | m15 R4 | 10 代 i7/i9 | 30 系 | |
m15 R5 | 锐龙 R7-5800H | 30 系 | ||
m15 R6 | 11 代 i7 | 30 系 | ||
m15 R7 | 12 代 i7 | 30 系 | 2022年2月 | |
x15 R1 | 11 代 i7/i9 | 30 系 | ||
x15 R2 | 12 代 i9 | 30 系 | 2022年2月 | |
16.0 英寸 | m16 | 13 代 i7/i9 | 40 系 | 2023年2月 |
x16 | 13 代 HK | 40 系 | 2023年2月 | |
17.3 英寸 | m17 R3 | 10 代 i7 | 20 系 | |
m17 R4 | 10 代 i7 | 30 系 | ||
m17 R5 | 锐龙 R7/R9 | 30 系 | 2022年3月 | |
x17 R1 | 11 代 i7/i9 | 30 系 | ||
x17 R2 | 12 代 i9K | 30 系 | 2022年2月 | |
18英寸 | m18 | 13 代 i9 | 40 系 | 2023年2月 |
x15 是板载内存,x17 是卡槽内存
x 系列屏幕有 1K165Hz / 1K360Hz / 2K240Hz(15寸独有)/ 4K120Hz(17寸独有)
x 系列有 2 个 M.2 硬盘位,没有 2.5 寸硬盘位
Area-51m R(数字):可拆 CPU
Area-51m R2:10 代 i7,20 系显卡
以上规则整理于 2021 年 7 月,随着时间的推移,以上信息将逐渐失效。
在数据库连接字符串可设置是否将 tinyint(1) 映射为 bool,否则为 sbyte:
TreatTinyAsBoolean=false/true
tinyint(1) 一般用于表示 bool 型字段,存储内容为 0 或 1,但有时候也用来存储其它数字。
以 Discuz! 的表 pre_forum_post 为例,字段 first 和 invisible 都是 tinyint(1),但 first 只储存 0 和 1,invisible 却有 -1、-5 之类的值。
因此我们一般设置 TreatTinyAsBoolean=false,程序中 first 与 invisible 均以 sbyte 处理。
设置 TreatTinyAsBoolean=true 后,EF 或 EF Core 自动将该类型映射为 bool,方便在程序中作进一步处理。
一旦设置 TreatTinyAsBoolean=true,那么所有查询结果中 tinyint(1) 字段的返回值永远只有 1 和 0(即 True/False),即使真实值为 -1,也返回 1。
因为我们必须在确保所有的 tinyint(1) 类型字段都仅表示布尔值是才设置 TreatTinyAsBoolean=true。
一旦部分 tinyint(1) 类型字段用于存放 0 和 1 以外的数,那么就应该设置 TreatTinyAsBoolean=false。
在数据库优先的项目中,以 TreatTinyAsBoolean=false 生成数据模型后,可将明确为布尔类型的字段改为 bool。列出 MySQL 数据库中所有表所有字段中类型为 tinyint(1) 的字段值
以 .edmx 为例:
在项目中搜索该字段名,在搜索结果中找到 .edmx 文件中的两处。
.edmx 文件中的注释已经表明其包含 SSDL、CSDL、C-S mapping 三块内容,
在 SSDL content 下方找到该字段:
<Property Name="字段名" Type="tinyint" Nullable="***" />
改为
<Property Name="字段名" Type="bool" Nullable="***" />
在 CSDL content 下方找到该属性:
<Property Name="属性名" Type="SByte" Nullable="***" />
改为
<Property Name="属性名" Type="Boolean" Nullable="***" />
在解决方案管理器中展开 .edmx ->库名.tt -> 表名.cs 文件,
将模型类中的属性
public sbyte invisible { get; set; }
改为
public bool invisible { get; set; }
或 sbyte? 改为 bool?。
在 EF Core 中,直接打开对应数据表的 .cs 文件,更改属性类型即可。
相关报错:
错误: 指定的成员映射无效。类型中的成员的类型“Edm.SByte[Nullable=False,DefaultValue=]”与类型中的成员的“MySql.bool[Nullable=False,DefaultValue=]”不兼容。
InvalidOperationException: The property '***' is of type 'sbyte' which is not supported by the current database provider. Either change the property CLR type, or ignore the property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
尝试先连接一次能解决此问题(概率),非常的莫名其妙:
using Data.Discuz.db_bbs2021Context dbd = new();
var conn = dbd.Database.GetDbConnection();
conn.Open();
conn.Close();
参考:
https://mysqlconnector.net/connection-options/
https://stackoverflow.com/questions/6656511/treat-tiny-as-boolean-and-entity-framework-4
2023年1月注:本文适用于 Pomelo.EntityFrameworkCore.MySql 6.0,升级到 7.0 后会出现:
System.InvalidOperationException:“The 'sbyte' property could not be mapped to the database type 'tinyint(1)' because the database provider does not support mapping 'sbyte' properties to 'tinyint(1)' columns. Consider mapping to a different database type or converting the property value to a type supported by the database using a value converter. See https://aka.ms/efcore-docs-value-converters for more information. Alternately, exclude the property from the model using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.”
Orbi 型号命名规则:
套装:RBK
主体:RBR
分身:RBS、RBW 等
套装对比:
CPU | 高通 IPQ4019 四核 717MHz | 四核 710MHz | ||||
ROM | 128MB | - | - | - | - | - |
内存 RAM | 256MB DDR3 | 512MB | ||||
闪存 Flash | - | 256MB | 4GB | |||
包装内容 | 2 个(不分子母) | 1 个 RBR10 1 个 RBS10 | 1 个 RBR20 1 个 RBS20 | 1 个 RBR40 1 个 RBW30 插墙式 | 1 个 RBR40 1 个 RBS40 | 1 个 RBR50 1 个 RBS50 |
速度 | AC1300 双频段 1300Mbps 电力线 1000M 有线 | AC1200 双频段 2.4GHz 300Mbps+5GHz 866Mbps | 三频段 AC2200 本体 AC2200 分身 (866回程+866+400Mbps) | 三频段 AC3000 本体 AC3000 分身 (1733回程+866+400Mbps) | ||
本体端口 | 每个主机 3 个 WAN/LAN 自适应以太网端口 | 1 WAN & 1 LAN | 1 WAN & 1 LAN | 1 WAN & 3 LAN | 1 WAN & 3 LAN & 1 USB 2.0 | |
分身端口 | - | 2 LAN | - | 4 LAN | 4 LAN & 1 USB 2.0 | |
天线 | 4根 | 6根 | ||||
以太网回程 | 支持 | 支持 | ||||
Daisy Chain Topology 菊花链 | 支持 | |||||
Beamforming 波束成形 | 支持 | |||||
MU-MIMO | 支持 | |||||
802.11k/v 快速漫游 | 支持 | |||||
802.11r 快速漫游 | 不支持 | |||||
802.11ax(Wi-Fi 6) | 不支持 | |||||
AP 模式 | 不支持 | 支持 | ||||
关闭 WiFi 双频合一 | 原厂不支持,小米和 RBK50 可通过修改实现,分离后有线回程可能会失效 | |||||
IPv6 | 支持 | |||||
带机量 | 248 | |||||
覆盖范围 | - | 418 平方米 | 250 平方米 | 200 平方米 | 250 平方米 | 350 平方米 |
官网价 | 229.99 美元 | - | - | - | - | |
京东自营 | ||||||
京东旗舰店 | - | |||||
天猫旗舰店 | - | |||||
其它天猫店 | 969 苏宁易购 | - | RBK30:1288 | RBK40:1699 | - | |
优势 | 管理功能丰富。 配合米家APP 设置小米智能家居设备入网时,无需手动输入密码,入网更便捷。 网口盲插,不分子母。后续再扩展两个分身时可直接购买套装充当两个分身,相对于 Orbi 购买两个分身要节省成本。 | 三频。 性能稳定。 大内存 |
分体价格:
本体 RBR20:599
本体 RBR40:999
本体 RBR50:999 活动
分身 RBS20:699
分身 RBW30 插墙:999
分身 RBS40:1099
分身 RBS50:1449
分身 RBS50Y 室外:未知
价格采自2019年8月
主体/分身 匹配:
分身 RBS20 可作为 RBR20, RBR40 or RBR50 的卫星
分身 RBW30 可作为 RBR40 or RBR50 的卫星
分身 RBS40 可作为 RBR40 or RBR50 的卫星
分身 RBS50 可作为 RBR50 的卫星
分身 RBS50Y 可作为 RBR50 or RBR40 or SRR60 的卫星
RBK13 = 1个 RBR10 + 2个 RBS10
RBK20 = 1个 RBR20 + 1个 RBS20
RBK23 = 1个 RBR20 + 2个 RBS20
RBK30 = 1个 RBR40 + 1个 RBW30
RBK33 = 1个 RBR40 + 2个 RBW30
RBK40 = 1个 RBR40 + 1个 RBS40
RBK43 = 1个 RBR40 + 2个 RBS20
RBK44 = 1个 RBR40 + 3个 RBS20
RBK50 = 1个 RBR50 + 1个 RBS50
RBK53 = 1个 RBR50 + 2个 RBS50
扩展阅读:Mesh 路由器有线回程布线方案
完整操作步骤如下:
安装 NuGet 包:
Microsoft.AspNet.Web.Optimization
打开
Views
目录(如果是应用于区域,则为区域的Views
目录)中的 web.config,在<namespaces />
节点中添加<add namespace="System.Web.Optimization" />
在
App_Start
目录中创建类文件BundleConfig.cs
,更改其命名空间为应用程序的默认命名空间(即移除.App_Start
),创建方法:public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new StyleBundle("~/虚拟路径(不能有点)").Include("~/CSS文件路径")); bundles.Add(new ScriptBundle("~/虚拟路径(不能有点)").Include("~/JS文件路径")); }
虚拟路径应避免与页面访问路径相同。Include 可包含多个文件,效果是合并输出,注意引用的顺序。
打开
Global.asax
,在Application_Start()
事件中添加代码BundleTable.EnableOptimizations = true; // 该设置使在开发模式中实现压缩代码,不设置则仅在发布后压缩代码 BundleConfig.RegisterBundles(BundleTable.Bundles);
视图页面中引用样式表或脚本
@Styles.Render("~/CSS虚拟路径") @Scripts.Render("~/JS虚拟路径")
使用 Render 的好处是,ASP.NET 会自动给引用地址加上参数,可在更改脚本或样式表内容后更改这些参数使浏览器缓存立即失效。
如果你的项目中已经安装并使用 Bundle
,那么只需要参考第 4 步,将 BundleTable
的 EnableOptimixations
设为 true
。
以下是一些常见异常的解决方法:
The name 'Styles' does not exist in the current context
The name 'Scripts' does not exist in the current context
解决:参步骤 2。
引用的样式表或脚本不存在(报 404
错误)
解决:步骤 3 中的虚拟路径不规范。
今天发现,阿里云 CDN 的 Refer 防盗链并没有真正防止白名单外的域名调用 OSS 的图片。经过一番研究发现,这跟 https 有关。
我在阿里云开通了 OSS 来存在图片,并使用 CDN 访问,在 CDN 中开启了 https,但并不强制。并且使用“白名单”的方式来设置 Refer 防盗链。关键是开启了“允许空 Referer”。
我在 http://b.com/ 上测试调用 http 和 https 的图片都是打不开的(防盗链有效),但是在 https://b.com/ 上却能显示 http 的图片(防盗链失效):
究其原因,是 https 页面在调用 http 图片时请求头不包含 Referer 字段,导致 CDN 判断 Referer 为空,这时候如果开启了为空也允许访问的话,就会出现防盗链失效的情况了。
总结:如果 CDN 开启了 https 访问,那么不要允许空 Referer。这里白名单内的网站必须使用与 CDN 一致的 protocol(http 或 https)。建议的写法是:
<img src="//cdn.xxx.com/abc.jpg" />
前提:
若需获取用户 unionid,则小程序必须已绑定到微信开放平台。
小程序调用 wx.login(),将 code 发送到开发者服务器
开发者服务器请求微信接口 code2Session,获得 session_key、openid,有机会获得 unionid(参 UnionID 机制说明)。因此无需任何用户授权即可获取 openid
访问须要已获取用户信息的页面时,可通过小程序端使用 button + getUserInfo 的方式请求用户授权
访问须要已获取手机号码的页面时,可通过小程序端使用 button + getPhoneNumber 的方式请求用户授权
code2session、getUserInfo、getPhoneNumber 等接口返回数据存入数据库 dt_weapp_user
服务端的任何接口均返回口令状态包(含自定义会话口令等信息),小程序端应保存于 storage
请求 getUserInfo 后应判断 detail.errMsg 是否为 getUserInfo:ok,请求 getPhoneNumber 后应判断 detail.errMsg 是否为 getPhoneNumber:ok
授权窗口的弹出情况参此文
口令状态包是用来传递到客户端用来标识用户唯一凭证的,包含字段:会话口令(自定义用户凭证)、会话口令有效时间(秒)、是否已获取 unionid 或昵称(视业务需求)、是否已获取手机号码、uid(可选),以及其他用来标识业务身份字段。服务端可根据会话口令从数据库中获取该用户的所有已知信息。
一般情况下,当已获取手机号码时,uid 必有值,否则,uid 必为空。因此 uid 不是必须传递到客户端的。
通过 code2Session 获得的 session_key、以及 openid、unionid、手机号码等机密信息不允许包含在口令状态包中并缓存在客户端,客户端需要用到手机号码时单独调用接口获取。
若业务不要求以手机号码作为用户唯一标识,那么口令状态包中不需要包含是否已获取手机号码,仅 uid 即可。在客户端访问须要业务用户登录的页面时,也仅判断 uid 有值即可。
流程图:
为更好地适应 2017.7.19 发布的《小程序内用户帐号登录规范调整和优化建议》,开发者服务器提供的所有业务逻辑接口的返回值中都应包含口令状态包,约定有以下相关的返回值和处理动作(返回值按个人喜好来定):
口令状态 | 接口返回 | ASP.NET Web API 语句 | 处理动作 |
access_token 空或失效 | 401 状态码 | return Unauthorized(); | login() + code2Session,获取 openid,生成 access_token |
access_token 有效,但未获取 uniond 或用户信息 | 401 状态码,http 头 WWW-Authenticate 中标注 getUserInfo | return Unauthorized(new AuthenticationHeaderValue("getUserInfo")); | getUserInfo() |
access_token 有效,但未获取手机号码(即未找到业务用户) | 401 状态码,http 头 WWW-Authenticate 中标注 getPhoneNumber | return Unauthorized(new AuthenticationHeaderValue("getPhoneNumber")); | getPhoneNumber() |
WWW-Authenticate 有大小写的问题,千万别入坑,参:https://xoyozo.net/Blog/Details/header-www-authenticate
返回内容是根据业务逻辑在服务端决定的,客户端在处理每个接口返回值时对返回内容作相应的处理即可。
功能 | 适用场景 | |
wx.switchTab | 跳转到 tabBar 页面,并关闭其他所有非 tabBar 页面。 | 在应用内的某个页面上处理事务完毕,需要跳转到 tabbar 页面时使用 |
wx.reLaunch | 关闭所有页面,打开到应用内的某个页面。 | 当在任何页面判断登录失效时跳转到授权登录页(当所有页面都需要登录后才能访问的情况) |
wx.redirectTo | 关闭当前页面,跳转到应用内的某个页面。但是不允许跳转到 tabbar 页面。 | 跳转到非 tabbar 页面,无返回按钮,目标页面必须具有跳转到小程序其它页面的功能 |
wx.navigateTo | 保留当前页面,跳转到应用内的某个页面。但是不能跳到 tabbar 页面。 | 跳转到非 tabbar 页面,有返回按钮 |
wx.navigateBack | 关闭当前页面,返回上一页面或多级页面。可通过 getCurrentPages 获取当前的页面栈,决定需要返回几层。 | 返回 |
注册苹果开发者账号和发布 App 会填写一些联系邮箱,一旦账号或应用违规,苹果方也只会以解决方案中心或邮件的形式通知开发者,一旦超过时限,可能会采取一些强制措施,影响到我们的 App 正常上架运营,本文罗列了一些相关的电子邮箱,如有不全请指正。
在注册 Apple ID (https://appleid.apple.com/account/manage)时会填写 3 个邮箱,一个用于登录用户名,一个作为常规联系,第 3 个是用于救援(估计是常规联系邮箱失效时才会用到)。
在 App Store Connect (https://appstoreconnect.apple.com/)中发布新版本 App 时会填写两个邮箱,一个是 App 的联系邮箱,一个是审核联系邮箱。
当我们在联系审核团队(https://developer.apple.com/contact/app-store/)时,可能会填写一个邮箱,用于针对当前问题进行反馈。
苹果的“联系我们”(https://developer.apple.com/contact/)
其它一些主动提交的信息,用于反馈,如:投诉侵犯知识产权(https://www.apple.com/legal/internet-services/itunes/appstorenotices/#?lang=zh)
当使用在线编辑器编辑一篇文章(或从 Word 复制)后,会得到包含 HTML 标签的字符串内容,可以直接将它输出到页面上而不需要进行 HTML 编码。
但是,当我们需要改变图片大小时,我们发现有些图片的尺寸是直接使用 style 属性固定的,除了用 JS 进行后期处理,我们可以在服务端对 <img /> 进行修正。
这个场景会在小程序开发的时候遇到。
网上一般使用正则表达式直接将 <img
替换成 <img style="max-width: 100%; height: auto;"
,缺点是如果该 <img /> 本身就带有 style 属性,那么会出现一个标签两个 style,很多情况导致这两个样式同时失效,所以我们应针对有 style 和无 style 分别处理。
// 把 <img src="a.jpg" style="display: block;" /> 替换成 <img src="a.jpg" style="display: block;;max-width:100%;height:auto;" />
Content = Content.replace(/(\<img\s+[^>]*style\s*\=\s*['"][^'"]*)(['"])/gi, '$1;max-width:100%;height:auto;$2');
// 把 <img src="b.jpg" /> 替换成 <img src="b.jpg" style="max-width:100%;height:auto;" />
Content = Content.replace(/(\<img\s+((?!style).)+?)(\/?>)/gi, '$1 style="max-width:100%;height:auto;" $3');
复制以上代码时,半角空格可能会变成全角空格,请注意修正。
当有 style 时,我们将 max-width: 100%; height: auto;
追加在原样式之后,以重写原样式。这里没有直接判断原样式是否以 ;
结尾,而是直接追加 ;
,这并不会影响实现展示效果。
在判断没有 style 用到正则表达式的“断言”,参:https://blog.csdn.net/xuyangxinlei/article/details/81359366