博客 (175)

【推荐】临时口令和会话口令合二为一的流程(适合随时授权)


前提:

小程序已绑定到微信开放平台。


分两种场景:

场景一:仅需要获取 unionid,且不需要获取头像昵称等用户信息,且已经有很大部分用户仅通过 code2Session 就能获取到 unionid(如:已关注了绑定同一微信开放平台的其它公众号,参 UnionID 机制说明);

场景二:仅需要获取 unionid,或需要获取 unionid 及头像昵称等用户信息,或很大部分用户不能通过 code2Session 获取到 unionid。


场景一步骤:

  1. 小程序调用 wx.login(),将 code 发送到开发者服务器

  2. 开发者服务器请求微信接口 code2Session,获得 session_key、openid,有机会获得 unionid

  3. 若没有返回 unionid,尝试用 openid 从数据库中获取 unionid

  4. 如果数据库中没有找到对应的 unionid,告知小程序端使用 button + getUserInfo 的方式请求用户授权

  5. 授权允许(判断 detail.errMsg 是否为 getUserInfo:ok)则将加密数据传回开发者服务器进行解密,得到 unionid、头像、昵称等信息,保存到数据库

  6. 若授权拒绝,则无动作,用户再次点击 button 会重新弹起授权框

* 该流程仅部分用户的首次使用才要求授权。其它注意事项和流程细节见下方流程图。


场景二步骤:

  1. 小程序调用 wx.login(),将 code 发送到开发者服务器

  2. 开发者服务器请求微信接口 code2Session,获得 session_key、openid

  3. 尝试用 openid 从数据库中获取 unionid 和/或 用户信息

  4. 如果数据库中没有找到对应的 unionid 和/或 用户信息,告知小程序端使用 button + getUserInfo 的方式请求用户授权

  5. 授权允许(判断 detail.errMsg 是否为 getUserInfo:ok)则将加密数据传回开发者服务器进行解密,得到 unionid、头像、昵称等信息,保存到数据库

  6. 若授权拒绝,则无动作,用户再次点击 button 会重新弹起授权框

* 该流程仅每个用户的首次使用才要求授权。其它注意事项和流程细节见下方流程图。


上述两种场景的设计流程,只要数据库中已保存用户的 unionid(和/或 用户信息),都不再需要用户再次授权(即使在“设置”中关闭了“用户信息”授权,点击小程序右上角三点按钮,选择关于小程序,点击右上角的三点,选择设置)。


场景一流程图:

微信小程序授权登录获取 unionid(仅部分用户的首次使用才要求授权).png

场景二流程图:

微信小程序授权登录获取 unionid、头像昵称等(仅首次使用才要求授权).png


流程图中的“临时口令”仅用于关联“通过 code2Session 获得的 session_key”,并在用户授权后带回换取 session_key。原因是 session_key 是机密数据,不允许被传到小程序端。临时口令用完即删(设置表 dt__weapp_code2session 中相应记录的该字段为空)。


【推荐】临时口令和会话口令合二为一的流程(适合随时授权)

xoyozo 6 年前
11,360
.psd安装 SageThumbs
.pdf

打开 Acrobat DC 或 Acrobat Reader DC。在“编辑”菜单中,选择“首选项”。

在“首选项”对话框中,选择“种类”列表中的“一般”,然后选中“在 Windows 资源管理器中启用 PDF 缩略图”复选框。

官方指南


xoyozo 6 年前
3,477

如果你是刚入手的小米 WiFi 电力猫,那么按说明书一步一步配置即可。这里记录一下移机的重置方法。

本次移机的场景是电力猫从一台小米路由器更换到另一台小米路由器的配置,两台小米路由器 WIFI 的 SSD 不同(假设为 WIFI-A 和 WIFI-B)。

错误做法:打开米家,切换到 WIFI-B 所在的房间,点击右上角的添加新设备,根据介绍插上子猫,并按子猫的配置键 5 秒以上。连上“xiaomi-plc-xxx”,米家显示正在连接,但到达 100% 后显示连接超时。

可能的错误原因

  1. 没有插上主猫

  2. 该电子猫已经在米家上添加过了(在 WIFI-A 所在的房间),就无法添加到其它房间了(仅猜测,未实测)

于是,同时插上主猫和子猫,并且路由器和主猫使用网线连接,什么都不设置,过一两分钟,两猫自动会变成蓝灯(表示连接成功)。这时,如果刚才那步没有重置成功的话,打开米家主界面上的“小米电力线wifi扩展器”(如果没有删除过,还在 A 房间),里面会显示网络名称为 WIFI-A,还可能没有开“WIFI漫游”。这样虽然能连接上网,但有两个 SSD,不能实现漫游。

这时,按子猫配置键 5 秒以上,并静等一分钟以上,变回蓝灯后,再打开米家,就会看到网络名称可能是 WIFI-B-Plus,这时"WIFI漫游”也能打开了,完美扩展了 WIFI。

综上实践得出

WIFI 是由子猫负责的,所以跟 SSD 有关的配置由子猫负责;

一台设备(这里指电子猫套餐)只能添加到米家一次,但可以更改设备所在的房间。

正确的重置电力猫步骤是

  1. 同时插上主猫和子猫

  2. 主猫连上路由器

  3. 子猫按配置键 5 秒以上,等待一分钟以上

  4. 打开米家,进入“小米电力线wifi扩展器”,打开 WIFI 漫游

以上仅在使用小米路由器情况下实测,非小米路由器未尝试。

xoyozo 6 年前
60,906
二维码类型可扫码授权的微信号
其它微信号
直接扫码将二维码截图发送给可扫码授权的微信号无需劳烦管理员的方式
登录微信公众平台管理员与运营者

扫码后需管理员验证登录(管理员通过“公众平台安全助手”接收消息,点开详情后点击“确定”)

授权人用摄像头扫码,点击“确定”
成为运营者
设置公众号IP白名单管理员与长期运营者无法完成授权人用摄像头扫码,点击“确定”
成为长期运营者
公众号绑定运营者管理员无法完成管理员用摄像头扫码,点击“确定”

小程序添加/删除项目成员

管理员无法完成管理员直接识别二维码,点击“确定”
小程序修改名称、修改简称、修改登录邮箱、修改密码管理员无法完成“修改简称”管理员用摄像头扫码,点击“确定”,其它未测
小程序修改业务域名
管理员、有“开发者”权限的项目成员无法完成授权人直接识别二维码,点击“确定”成为有“开发者”权限的项目成员
微信开放平台绑定小程序管理员无法完成管理员用摄像头扫码,点击“确定”

① 摄像头扫码:无法直接用“识别二维码”,必须把二维码发送到身边的其它设备,再使用手机摄像头完成扫码

② 成为运营者要求绑定银行卡;成为运营者将占用“微信号绑定的帐号”数量,详见说明。若达到上限,只有法定代表人可继续成为运营者。在公众号“公众平台安全助手”中可查询绑定的帐号。

另外:

  • 小程序添加/删除体验成员无须管理员授权

  • 如果管理员未关注公众号“公众平台安全助手”,待测……

xoyozo 6 年前
4,690

当使用在线编辑器编辑一篇文章(或从 Word 复制)后,会得到包含 HTML 标签的字符串内容,可以直接将它输出到页面上而不需要进行 HTML 编码。

但是,当我们需要改变图片大小时,我们发现有些图片的尺寸是直接使用 style 属性固定的,除了用 JS 进行后期处理,我们可以在服务端对 <img /> 进行修正。

这个场景会在小程序开发的时候遇到。

我们可以在客户端用 JS 进行处理,也可以在服务端用类似的方法处理(使用正则表达式)。参此文

这里使用 HtmlAgilityPack 通过递归节点来处理:

/// <summary>
/// 给所有指定节点添加样式
/// </summary>
/// <param name="html"></param>
/// <param name="tag">节点名称(小写),如:img</param>
/// <param name="styles">要添加的样式,如:max-width:100%;</param>
/// <returns></returns>
public static string AddStyleToHtmlNode(string html, string tag, string styles)
{
    HtmlDocument doc = new HtmlDocument();
    doc.LoadHtml(html);

    for (var i = 0; i < doc.DocumentNode.ChildNodes.Count; i++)
    {
        doc.DocumentNode.ChildNodes[i] = AddStyleToHtmlNode(doc.DocumentNode.ChildNodes[i], tag, styles);
    }

    return doc.DocumentNode.OuterHtml;
}
private static HtmlNode AddStyleToHtmlNode(HtmlNode node, string tag, string styles)
{
    if (node.Name == tag)
    {
        var style = node.GetAttributeValue("style", null);
        node.SetAttributeValue("style", ((string.IsNullOrWhiteSpace(style) ? "" : style.Trim() + ";") + styles).Replace(";;", ";"));
    }
    for (var i = 0; i < node.ChildNodes.Count; i++)
    {
        node.ChildNodes[i] = AddStyleToHtmlNode(node.ChildNodes[i], tag, styles);
    }
    return node;
}

直接调用:

Content = zStringHTML_190126.AddStyleToHtmlNode(Content, "img", "max-width:100%;height:auto;");


xoyozo 6 年前
4,534

当使用在线编辑器编辑一篇文章(或从 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

延伸阅读:C# 用 HtmlAgilityPack 给 HTML 节点加上 style

xoyozo 6 年前
5,457

一、显示信息的命令

console.log("normal");           // 用于输出普通信息
console.info("information");     // 用于输出提示性信息
console.error("error");          // 用于输出错误信息
console.warn("warn");            // 用于输出警示信息

 

二、点位符:字符(%s)、整数(%d或%i)、浮点数(%f)和对象(%o);

console.log("%s","string");                 //字符(%s)
console.log("%d年%d月%d日",2016,8,29);       //整数(%d或%i)
console.log("圆周率是%f",3.1415926);         //浮点数(%f)
var dog = {};
dog.name = "大毛";
dog.color = "黄色";
dog.sex = "母狗";
console.log("%o",dog);                      //对象(%o)


 

三、信息分组 (console.group(),console.groupEnd())

console.group("第一组信息");
    console.log("第一组第一条:我的博客");
    console.log("第一组第二条:CSDN");
console.groupEnd();

console.group("第二组信息");
    console.log("第二组第一条:程序爱好者QQ群");
    console.log("第二组第二条:欢迎你加入");
console.groupEnd();

 

 

四、将对象以树状结构展现 (console.dir()可以显示一个对象所有的属性和方法)

var info = {
    name : "Alan",
    age : "27",
    grilFriend : "nothing",
    getName : function(){
        return this.name;
    }
}
console.dir(info);


 

五、显示某个节点的内容 (console.dirxml()用来显示网页的某个节点(node)所包含的html/xml代码)

var node = document.getElementById("info");
node.innerHTML += "<p>追加的元素显示吗</p>";
console.dirxml(node);

 

六、判断变量是否是真 (console.assert()用来判断一个表达式或变量是否为真,只有表达式为false时,才输出一条相应作息,并且抛出一个异常)

var testObj = false;
console.assert(testObj, '当testObj为false时才输出!');

 

七、计时功能 (console.time()和console.timeEnd(),用来显示代码的运行时间)

console.time("控制台计时器");
for(var i = 0; i < 10000; i++){
    for(var j = 0; j < 10000; j++){}       
}
console.timeEnd("控制台计时器");

 

八、性能分析performance profile (就是分析程序各个部分的运行时间,找出瓶颈所在,使用的方法是console.profile()和console.proileEnd();) 

function All(){
    // alert(11);
    for(var i = 0; i < 10; i++){
        funcA(100);
    }
    funcB(1000);
}
function funcA(count){
    for(var i = 0; i < count; i++){};
}
function funcB(count){
    for(var i = 0; i < count; i++){};
}
console.profile("性能分析器");
All();
console.profileEnd();

详细的信息在chrome控制台里的"profile"选项里查看

 

九、console.count()统计代码被执行的次数

function myFunction(){
    console.count("myFunction 被执行的次数");
}
myFunction();       //myFunction 被执行的次数: 1
myFunction();       //myFunction 被执行的次数: 2
myFunction();       //myFunction 被执行的次数: 3


 

十、keys和values,要在浏览器里输入

 

 

十一、console.table表格显示方法

  var mytable = [
    {
        name: "Alan",
        sex : "man",
        age : "27"
    },
    {
        name: "Wu",
        sex : "gril",
        age : "28"
    },
    {
        name: "Tao",
        sex : "man and gril",
        age : "29"
    }
]
console.table(mytable);


 

十二、Chrome 控制台中原生支持类jQuery的选择器,也就是说你可以用$加上熟悉的css选择器来选择DOM节。

$("body");           //选择body节点

 

十三、copy通过此命令可以将在控制台获取到的内容复制到剪贴板

copy(document.body);                      //复制body
copy(document.getElementById("info"));    //复制某id元素的的节点

 

十四、$_命令返回最近一次表达式执行的结果,$0-$4代表了最近5个你选择过的DOM节点

 

 

十五、利用控制台输出文字,图片,以%c开头,后面的文字就打印的信息,后面一个参数就是样式属性;

console.log("请在邮件中注明%c 来自:console","font-size:16px;color:red;font-weight:bold;");

 


A
转自 AlanTao 6 年前
4,477

这是一个数据可视化项目,基于D3.js。能够将历史数据排名转化为动态柱状图图表。

先来看看效果:

https://xoyozo.net/Demo/BarGraph

作者 Jannchie 见齐还提供了官方视频教程:

https://www.bilibili.com/video/av28087807

不过由于开源项目的不断更新,该教程的部分内容已失效,本文针对 2018-12-25 版本总结了一些常用的配置说明,仅供参考。


从 GitHub 下载源代码,在 src 目录中可以看到 4 个文件:

bargraph.html --> 运行示例页面

config.js --> 配置文件

stylesheet.css --> 样式表

visual.js --> 核心文件


作者并没有将代码封装为插件的方式,所以我们是通过修改 config.js 配置文件的方式应用到自己的项目中的。

visual.js 虽然是核心文件,但作者将部分示例中的代码也包含其中,但并不影响我们直接在自己的项目中引用。

以下是 config.js 中的主要属性:

属性说明参考值
encoding数据源(csv、json)等的文件编码GBK / UTF-8 等
max_number每个时间节点最多显示的条目数10
showMessage控制是否显示顶部附加信息文字true / false
auto_sort时间自动排序(详细含义、作用及限制见代码中注释)true / false
timeFormat时间格式,显示于图表右下角的时间%Y、%Y-%M-%D 等
reverse是否倒序true / false
divide_by类型根据什么字段区分?如果是 name,则关闭类型显示
divide_color_by

颜色根据什么字段区分?

须要注意的是,如果配置成 name,则各条颜色不同(因为 name 值各异),如果配置成 type 等,那么相同 type 值的条颜色相同。

字段名
color指定部分或所有条的颜色,该项与 divide_color_by 设置有关。

以 divide_color_by = 'name' 为例,"中国"是其中的一项 name 值,那么该项将显示 #D62728 色:

color: {

      '中国': '#D62728'

}

changeable_color若 true 则颜色的深浅将根据数据的增长率实时改变
itemLabel
左边文字
typeLabel右边文字
item_x


interval_time
时间点间隔时间2
text_y


text_x


offset


display_barInfo如果希望不显示,则可以设置较大的值,单位像素
use_counter

step

format格式化数值
left_margin

right_margin

top_margin

bottom_margin

dateLabel_x

dateLabel_y

allow_up

enter_from_0

big_value

use_semilogarithmic_coordinate

long

wait数据加载完成后开始播放前的等待时间0
update_rate


xoyozo 6 年前
9,150

当我们用 ASP.NET Web API 作服务端接口时,如果客户端以 GET 方式请求的 URL 中,由于拼接错误导致“?”和“&”并列出现,会发生 400 Bad Request,那么需要在 IIS 中使用 URL 重写模块来纠正。

请求 URL 如:

http://www.abc.com/api/obj?&foo=bar

需要重写为:

http://www.abc.com/api/obj?foo=bar


打开 IIS 管理器中对应网站的 URL 重写

image.png


添加空白规则。

匹配的 URL 不包含域名,如上述 URL 则匹配的范围是:

api/obj

不包含我们要查找的字符串 ?&,所以此处模式只能匹配所有:

.*

又因为重定向路径中需要包含这部分,所以用括号包裹,即:

(.*)

image.png

继续添加条件匹配:

条件输入:{QUERY_STRING},表示匹配查询字符串,

匹配的部分是“?”后面的字符串:

&foo=bar

那么可以填写模式:

^\&.*

因为 & 后面的部分仍然需要使用,所以用括号包裹:

^\&(.*)

image.png

“操作”中选择类型“重定向”,URL 填写:

{R:1}?{C:1}

其中 {R:1} 指代 api/obj,{C:1} 指代 foo=bar

取消“附加查询字符串”前面的勾

重定向类型在测试时可以选择 302 或 307,没问题后选择 301。

image.png

完成。

最终我们可以在网站的配置文件 web.config 中看到:

<rewrite>
    <rules>
        <rule name="uni-app-h5-replace-q" stopProcessing="true">
            <match url="(.*)" />
            <conditions>
                <add input="{QUERY_STRING}" pattern="^\&amp;(.*)" />
            </conditions>
            <action type="Redirect" url="{R:1}?{C:1}" appendQueryString="false" redirectType="Temporary" />
        </rule>
    </rules>
</rewrite>

我们要把这段代码复制到开发环境源代码的 web.config 中,以免发布网站时将我们设置好的配置覆盖掉。

xoyozo 6 年前
8,761

TIM图片20181126142732.png

uni-app 的 input,当 type = "text" 时,设置 confirm-type = "next" 可以提供键盘的“下一项”,通过 @confirm 触发设置下一个文本框的焦点,即可实现只操作键盘即可完成表单填写。

我们以从 a 组件跳转到 b 组件为例:

<input v-model="a" type="text" confirm-type="next" @confirm="moveNext('b')" />

uni-app 的组件只有属性和事件,不提供方法,那么我们只能设置提供了 focus 属性的组件的焦点。

<input v-model="b" :focus="focusList['b']" />

moveNext() 方法实现:

moveNext(dom){
	this.focusList[dom] = true;
}

当然 focusList 必须先定义并初始化,否则设置 focus 为 true 将失效:

data() {
	return {
		a: '',
		b: '',
		focusList: {
			b: false
		}
	}
}

几个注意点:

  • confirm-type = "next" 仅支持微信小程序

  • “下一项”按钮效果是一次性的,使用一次后再次在 a 上触摸“下一项”将不再跳转到 b,即使在 moveNext() 中先设置为 false 再设置为 true 也没用

  • 其它组件也可以通过自带的方法实现跳转到带 focus 属性的组件(如在 picker 的 @change 中设置 this.focusList['b'] = true)

  • 限制于 confirm-type = "next" 只当 type = "text" 时有效,因此非文本键盘(如数字键盘)就不能提供“下一项”功能

  • textarea 组件的右下角始终是“换行”,由其右上角的“完成”按钮来实现“下一项”功能

  • textarea 组件在“下一项”跳转过程中,组件可能会被 tabBar 遮挡(几率很大)

xoyozo 6 年前
9,040