0%

半角字符与全角字符

是计算机中,中、日、韩文的CJKV字符的显示格式。

传统上,英语或拉丁字母语言使用的计算机系统,每一个字母或符号,都是使用一字节的空间(一字节由8比特组成,共256个编码空间)来储存;而汉语、日语及韩语文字,由于数量大大超过256个,故惯常使用两字节来储存一个字符。在使用等宽字体(如DOS、部分文字编辑器等)的环境下,中日韩文字此时占据两倍于西文字符的显示宽度。所以,中、日、韩等文字称为全角字符,相比起来,拉丁字母或数字就称为半角字符。有时为了使字体看起来齐整,英文字母、数字及其他符号也由原来只占一个字空间,改为占用两个字的空间显示、使用两个字节储存的格式。

关于人民币元的符号

  • 半角: ‘¥’ U+00A5
  • 全角: ‘¥’ U+FFE5

贺老说:因为人民币符号多是与半角阿拉伯数字相邻使用而非在汉字文本流中独自出现,所以建议通常使用其半角版本,以保证货币符号与数字的空间关系及字体设计协调。全角人民币符号「¥」只是个历史遗留字符,如今通常不会用到,它和半角人民币符号「¥」也没有语义差异。


reference


原文链接

作为小程序第三方服务商,同一个小程序,可能会在线上存在不同的版本。
有时候,如果页面UI没有进行调整的情况下,我们就没法知道当前小程序究竟是哪一个版本。

先前想到了两个解决方案:

  • 方案一:

    在每次http请求中的header中带上version,这样既能知道小程序对应版本,后端也能根据version来做api的版本控制,向后兼任。但是弊端也很明显,如果想知道线上小程序的版本,必须通过抓包去查看header。

  • 方案二:

    通过在埋点数据加入version。弊端在于,需要登录后台去查看埋点数据。

直到今天,查看微信文档时,看到了这样一句话

在正式版打开调试还有一种方法,就是先在开发版或体验版打开调试,再切到正式版就能看到vConsole。 原文链接

这样,其实我们可以把版本直接console.log出来,当需要直到版本信息时,通过上面的方式,在正式版使用VConsole就可以啦。


原文链接

目前我司准备在小程序里通过web-view嵌套h5,希望在小程序调用api(wx.request()),然后server端通过api的header设置cookie。因为cookie均是通过http设置或者携带,以为这样,就可以在web-view里通过http请求(xhr或者fetch)带上小程序请求的api中设置的cookie。事实证明too young too naive

小程序没法设置cookie到web-view中

首先,我们启一个server,这个server目的在于返回一个get请求,并设置cookie, 接收一个post请求,用于查看http是否带上了cookie

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// app.js

const Koa = require('koa');
const cors = require('koa2-cors');
const Router = require('koa-router');
// cors 用于设置 http2 中的 CORS `Access-Control-Allow-Origin: *`
const app = new Koa();
const router = new Router();

router.get('/', (ctx, next) => {
ctx.cookies.set('mini-program', new Date().toISOString());
ctx.body = 'mini-program' + new Date().toISOString();
});

router.post('/', (ctx, next) => {
console.log('cookie:', ctx.request.header.cookie)
ctx.body = 'success';
});

app.use(router.routes())

app.use(cors({
credentials: true, // 用于跨域发送cookie,false cookie会被浏览器拦截
}));

app.listen(8082);

然后,我们仅仅看小程序请求,会不会带上cookie。

1
2
3
4
5
6
7
8
9
10
11
12
beforeMount: function() {
wx.request({
url: 'http://127.0.0.1:8082',
method: 'GET',
success: function() {
wx.request({
url: 'http://127.0.0.1:8082',
method: 'POST',
})
},
})
}

我们可以看到,http get 请求 response 的header里有一个Set-Cookie的字段,而post请求中,并没有把cookie带上。

那在webview里会怎样呢?

使用http-server在80端口启一个很简单的h5页面,该页面作用是发起以下请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<script>
var xhr = new XMLHttpRequest();
xhr.open('POSt', 'http://127.0.0.1:8082');
xhr.withCredentials = true; // 只有设置了这个,才能在跨域的情形下,带上cookie
xhr.send();
</script>
</body>
</html>

然后在小程序中的web-view中使用该url

1
<web-view wx:if="{{showWebView}}" src="http://127.0.0.1"></view-view>

确保发起了get请求后,再把 showWebView设置为true

可以看到,在web-view里的请求,header也没有cookie。

web-view如何使用小程序中的cookie

wx.request会返回http header,取到Set-Cookie这个字段,然后使用encodeURIComponent编码一下,通过url传给web-view,在web-view中通过document.cookie赋值。

小程序中如何模拟cookie

可以参考 一行代码让微信小程序支持 cookie

为什么小程序与web-view与不能共享cookie

小程序的wx.request()是通过jsCore调用系统原生api发起的请求,即便header里带有set-cookie,也不会在web-view对应的’浏览器’中设置cookie,而是由原生应用来处理这个header中的set-cookie,至于怎么操作,要看原生应用了。这个可以参考如何处理 iOS 原生网络请求中的 cookie ?

比较有趣的是,小程序中的web-view和微信中直接打开的h5,因为用的是同一个浏览器内核,所以,它们的cookie、storage是可以共享的。


原文链接

为什么需要进行小程序持续化集成与部署

小程序开发有别于web开发,我们开发好的代码,需要通过小程序开发工具上传到腾讯的服务器。预览我们开发好的小程序,也需要通过小程序开发者工具进行构建。
如果是一个人开发,这种通过在开发者本机并经过小程序开发者工具构建上传的方式不会有什么问题,但是,一旦同一个小程序开发的人员多了,就很容易因为开发环境不一致而出现种种问题。
而通过持续化集成,提供统一的构建环境,则可以避免这一问题。

实现原理

实际上,我们是在一台局域网mac上安装并注册了一个GitLab Runner(可以理解为一个用来执行软件集成脚本的容器,Runner可以分布在不同的主机上,同一个主机上也可以有多个Runner。),当GitLab-CI(一套配合GitLab使用的持续集成系统)检测到了变化,例如有新的push,会通知这台runner拉取新的代码,然后进行构建以及后续的操作。

代码编译完成后,我们使用小程序开发者工具提供的命令行工具进行代码上传。

当然,不一定要用mac, 只要能安装小程序开发者工具的设备,均可以。但是目前微信只提供了mac 和 windows版本的开发者工具,所以只能在基于mac 或者 windows系统上进行构建。

步骤

安装小程序开发工具

下载微信官方小程序开发者工具,并安装到GitLab Runner对应的设备上。

安装并配置 GitLab Runner

我们以mac系统为例:

安装GitLab Runner
1
2
sudo curl --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64
sudo chmod +x /usr/local/bin/gitlab-runner
注册GitLab Runner

首先,需要到GitLab管理界面中的Runners页面去找注册需要使用的token。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
gitlab-runner register

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://xxx.com/ (这里填写你gitlab的地址)
Please enter the gitlab-ci token for this runner:
xxxxxx (刚刚获取到的token)
Please enter the gitlab-ci description for this runner:
xxxxxx (随便填)
Please enter the gitlab-ci tags for this runner (comma separated):
wxapplet (这个我很重要,识别这个runner的标志)
Whether to run untagged builds [true/false]:
[false]: false
Whether to lock the Runner to current project [true/false]:
[true]: false
Registering runner... succeeded runner=xxxx
Please enter the executor: docker-ssh, virtualbox, docker+machine, docker-ssh+machine, docker, parallels, shell, ssh, kubernetes:
shell
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!
运行刚刚注册过的GitLab Runner
1
2
3
cd ~
gitlab-runner install
gitlab-runner start

此时,如果在GitLab管理页面中的Runner页面,你可以看到一个Tags名称为wxapplet的runner,说明注册成功。

编写 .gitlab-ci.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
image: node:latest

before_script:
- npm install

after_script:
- rm -r ./dist

cache:
paths:
- node_modules/

stages:
- build

build-package:
stage: build
tags:
- wxapplet
only:
- tags
script:
- regex="^prod-.*$"; if [[ $CI_COMMIT_TAG =~ $regex ]]; then npm run build; fi
- regex="^freeze-.*$"; if [[ $CI_COMMIT_TAG =~ $regex ]]; then npm run freeze; fi
- npm run deploy -- --tag ${CI_COMMIT_TAG}'

上面的文件表示,在build阶段,当push中带了tag时,将会启动build-package这个任务。GitLab Runner将会依次执行以上的script。前两个script表示,当以prod-或者freeze-开头时,才会执行当前的命令。

我们可以根据tag的不同,去执行不同的脚本。

因为我们使用了小程序开发的第三方框架,所以上面的npm run build或者npm run freeze,均是生成小程序所需代码到dist目录中。如果你没有使用框架开发小程序,可忽略这两部,直接npm run deploy

npm run deploy实际上执行了在package.json中定义的脚本"node ./deploy/index.js",并且将CI_COMMIT_TAG作为参数传入。

deploy/index.js

核心(伪)代码如下;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// tag 取传入的CI_COMMIT_TAG

let cmd = '';

// 同构tag中的login,可以控制小程序开发者工具进行登录。因为只有登录了才能上传代码。在对应项目的CI中,我们可以看到输出的二维码。

if (/^login.*$/.test(tag)) {
cmd = '/Applications/wechatwebdevtools.app/Contents/Resources/app.nw/bin/cli -l --login-qr-output';
} else {
cmd = `/Applications/wechatwebdevtools.app/Contents/Resources/app.nw/bin/cli --upload ${小程序版本}@${小程序dist所在目}/ --upload-desc ${这个版本的描述}`;
}

// 根据不同环境,将不同的project.config.json copy 到dist目录下。
if (/^prod-.*$/.test(tag)) {
execSync('cp ./deploy/prod/project.config.json ./dist/project.config.json');
}

if (/^freeze-.*$/.test(tag)) {
execSync('cp ./deploy/freeze/project.config.json ./dist/project.config.json');
}

const child = exec(
cmd,
(error) => {
if (error) {
throw error;
}
},
);

child.stdout.on('data', (data) => {
process.stdout.write(data);
});

child.stderr.on('data', (data) => {
process.stdout.write(data);
throw new Error('构建失败');
});

对于 project.config.json 的说明

v2-341399507f35a8a1a896761fd02f1d6b_r


参考: