在用 node.js 开发WebSocket 应用的时候,直接访问 端口号 WebSocket 是正常握手成功的,
但配了 Nginx 代理的 时候,握手却失败

最后配置如下 握手成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
server {
listen 80;
server_name lg.in;

location / {
proxy_pass http://127.0.0.1:4567/;
proxy_redirect off;

proxy_http_version 1.1;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-NginX-Proxy true;

proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}

}

关键点 就是 header 对应的 Upgrade

具体 HTTP Header 上的参数参考 SegmengFault 上的文章:
http://segmentfault.com/a/1190000000382788

如何使用 shipyard

安装

自动化安装脚本

1
curl https://nnn.li/docker/deploy | bash -s

快速删除 shipyard

1
curl https://nnn.li/docker/deploy | ACTION=remove bash -s

更新升级 shipyard

1
curl https://nnn.li/docker/deploy | ACTION=upgrade bash -s

增加一个节点

1
curl https://nnn.li/docker/deploy | ACTION=node DISCOVERY=etcd://<你的首次安装主机IP> bash -s

Launch a postgresql container

1
2
3
4
5
docker run --name gitlab-postgresql -d \
--env 'DB_NAME=gitlabhq_production' \
--env 'DB_USER=gitlab' --env 'DB_PASS=password' \
--volume /srv/docker/gitlab/postgresql:/var/lib/postgresql \
sameersbn/postgresql:9.4-12

Launch a redis container

1
2
3
docker run --name gitlab-redis -d \
--volume /srv/docker/gitlab/redis:/var/lib/redis \
sameersbn/redis:latest

Launch the gitlab container

1
2
3
4
5
6
7
docker run --name gitlab -d \
--link gitlab-postgresql:postgresql --link gitlab-redis:redisio \
--publish 10022:22 --publish 10080:80 \
--env 'GITLAB_PORT=10080' --env 'GITLAB_SSH_PORT=10022' \
--env 'GITLAB_SECRETS_DB_KEY_BASE=long-and-random-alpha-numeric-string' \
--volume /srv/docker/gitlab/gitlab:/home/git/data \
sameersbn/gitlab:8.4.2

login

1
2
username: root
password: 5iveL!fe

nvm安装 nodejs

获取nvm

1
2
3
4
5
6
7
8
root@iZ28krk4xlkZ:/home/git/node#   git clone https://github.com/creationix/nvm.git
Cloning into 'nvm'...
remote: Counting objects: 4399, done.
remote: Compressing objects: 100% (20/20), done.
remote: Total 4399 (delta 4), reused 0 (delta 0), pack-reused 4379
Receiving objects: 100% (4399/4399), 1.11 MiB | 23.00 KiB/s, done.
Resolving deltas: 100% (2578/2578), done.
Checking connectivity... done.

安装nvm

  • 下载之后,进入目录直行 ./install.sh
  • 安装之后输入 nvm 还是提示没有这时候需要直行 source ./nvm.sh

source /root/nvm/nvm.sh 写入 ~/.bashrc 或者其启动脚本中,
这样在系统启动的时候会自动执行这条指令。
开机就可以使用 nvm 了;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
root@iZ28krk4xlkZ:/home/git/node# ls
nvm
root@iZ28krk4xlkZ:/home/git/node# cd nvm/
root@iZ28krk4xlkZ:/home/git/node/nvm# ls
bash_completion CONTRIBUTING.md install.sh LICENSE.md Makefile nvm-exec nvm.sh package.json README.markdown test
root@iZ28krk4xlkZ:/home/git/node/nvm# ./install.sh
=> Downloading nvm from git to '/root/.nvm'
=> Cloning into '/root/.nvm'...
remote: Counting objects: 4399, done.
remote: Compressing objects: 100% (20/20), done.
remote: Total 4399 (delta 4), reused 0 (delta 0), pack-reused 4379
Receiving objects: 100% (4399/4399), 1.11 MiB | 15.00 KiB/s, done.
Resolving deltas: 100% (2578/2578), done.
Checking connectivity... done.
* (detached from v0.31.0)
master

=> Appending source string to /root/.bashrc
=> Close and reopen your terminal to start using nvm
root@iZ28krk4xlkZ:/home/git/node/nvm# source ./nvm.sh

nvm安装任意版本nodejs

  • 通过nvm ls查看当前已经安装的node或者iojs版本

  • 通过nvm ls-remote查看当前可以安装的node或者iojs版本

  • 通过nvm install 5.6.0 安装制定版本的nodejs

  • 通过nvm use 5.6.0 切换使用的nodejs版本

nvm install 5.0.0

1
2
3
4
5
6
7
8
9
10
11
12

root@iZ28krk4xlkZ:/home/git/node/nvm# nvm install 5.0.0
Downloading https://nodejs.org/dist/v5.0.0/node-v5.0.0-linux-x64.tar.xz...
##### 8.1%
curl: (56) SSL read: error:00000000:lib(0):func(0):reason(0), errno 104
Binary download failed, trying source.
######################################################################## 100.0%
Checksums empty
Now using node v5.0.0 (npm v3.3.6)
Creating default alias: default -> 5.0.0 (-> v5.0.0)
root@iZ28krk4xlkZ:/home/git/node/nvm# node -v
v5.0.0

nvm基本用法

1
2
3
4
5
6
7
nvm help:显示帮助信息
nvm --version:查看当前版本
nvm install [-s] <version>:下载安装nodejs/iojs
nvm uninstall <version>:卸载安装nodejs/iojs
nvm use <version> :切换 nodejs/iojs 版本
nvm ls:列出当前已安装的 nodejs/iojs
nvm ls-remote:列出当前可安装的nodejs/iojs

nvm详细文档

常用命令

查看容器的root用户密码

1
docker logs <容器名orID> 2>&1 | grep '^User: ' | tail -n1

因为docker容器启动时的root用户的密码是随机分配的。
所以,通过这种方式就可以得到redmine容器的root用户的密码了。

查看正在运行的容器

1
2
docker ps
docker ps -a //为查看所有的容器,包括已经停止的。

删除所有容器

1
2
3


docker rm $(docker ps -a -q)

删除单个容器

1
docker rm <容器名orID>

停止、启动、杀死一个容器

1
2
3
docker stop <容器名orID>
docker start <容器名orID>
docker kill <容器名orID>

查看所有镜像

1
docker images

删除所有镜像

1
2
3
4
5
docker rmi $(docker images | grep none | awk '{print $3}' | sort -r)

不行就用下面这个

docker rmi `docker images`

删除 所有 none 镜像

在删除 none 镜像时,先删除关联的 容器

1
docker rmi $(docker images | awk '/^<none>/ { print $3 }')

运行新容器

运行一个新容器,同时为它命名、端口映射、文件夹映射。以redmine镜像为例

1
docker run --name redmine -p 9003:80 -p 9023:22 -d -v /var/redmine/files:/redmine/files -v /var/redmine/mysql:/var/lib/mysql sameersbn/redmine

进入指定容器

docker ps 查询需要进入容器的 id

1
docker exec -it 40c330755e61 /bin/bash

查看容易 分配 的 ip

1
docker inspect --format='{{.NetworkSettings.IPAddress}}' $CONTAINER_ID

一个容器连接到另一个容器

1
2
docker run -i -t --name sonar -d -link mmysql:db   tpires/sonar-server
sonar

容器连接到mmysql容器,并将mmysql容器重命名为db。这样,sonar容器就可以使用db的相关的环境变量了。

拉取镜像

1
docker pull <镜像名:tag>

demo

1
docker pull sameersbn/redmine:latest

### 镜像迁移

当需要把一台机器上的镜像迁移到另一台机器的时候,需要保存镜像与加载镜像。

机器a

1
docker save busybox-1 > /home/save.tar

使用scp将save.tar拷到机器b上,然后:

1
docker load < /home/save.tar

构建自己的镜像

1
docker build -t <镜像名> <Dockerfile路径>

如Dockerfile在当前路径:

1
docker build -t xx/gitlab .

重新查看container的stdout

1
2
3
4
5
6
7
8
9
10
11
# 启动top命令,后台运行
$ ID=$(sudo docker run -d ubuntu /usr/bin/top -b)
# 获取正在running的container的输出
$ sudo docker attach $ID
top - 02:05:52 up 3:05, 0 users, load average: 0.01, 0.02, 0.05
Tasks: 1 total, 1 running, 0 sleeping, 0 stopped, 0 zombie
Cpu(s): 0.1%us, 0.2%sy, 0.0%ni, 99.7%id, 0.0%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 373572k total, 355560k used, 18012k free, 27872k buffers
Swap: 786428k total, 0k used, 786428k free, 221740k cached
^C$
$ sudo docker stop $ID

### 后台运行(-d)、并暴露端口(-p)

1
docker run -d -p 127.0.0.1:33301:22 centos6-ssh

### 从container中拷贝文件出来

1
sudo docker cp 7bb0e258aefe:/etc/debian_version .

拷贝7bb0e258aefe中的/etc/debian_version到当前目录下。

注意:只要7bb0e258aefe没有被删除,文件命名空间就还在,可以放心的把exit状态的container的文件拷贝出来

遇到的坑

权限问题

ubuntu14下的docker是没有service服务。去除每次sudo运行docker命令,需要添加组:

1
2
3
4
# Add the docker group if it doesn't already exist.
$ sudo groupadd docker
#改完后需要重新登陆用户
$ sudo gpasswd -a ${USER} docker
  • ubuntu14的febootstrap没有-i命令

  • Dockerfile中的EXPOSE、docker run –expose、docker run -p之间的区别

  • Dockerfile的EXPOSE相当于docker run –expose,提供container之间的端口访问。
  • docker run -p允许container外部主机访问container的端口

应用场景说明

在第一版的时候,我们尝试通过 Panli.com 主站 ifarme 厂家的各个页面,
由于涉及到浏览器安全的问题,浏览器阻住跨域 网站的操作 dom 信息 ;
我们只好尝试在 Panli 主站页面 设置遮罩层的方式来弥补
随着开发测试的进度一点点完成,最终发现 这个方案不可行

注入方案

在思考许久后, 原生 app 那边 说可以 执行 javascript代码 ;

后来我们就开始执行操作, 我们试着写了一下 执行 网页 dom 元素的 javascript 脚本

最终发现可以操作 web view 厂家页面的 dom 元素,可行性方案已找到。

开发敏捷

在开发注入脚本的时候,在手机上调试结果,非常痛苦,
浪费了大量的时间去小心意义的点击 web view 页面 的链接
测试机又不给力

无奈之下,既然都是注入 javascript 脚本 何不尝试在 pc 浏览器上一样注入呢;
我们开发了一套 基于 Chrome 浏览器的 插件 。

插件详细介绍 和 安装

淘宝首页头部元素寻找

可以看到在代码区域我看到了 id="v539213" class="v61dsk"

我们要录入的元素 就是 id=后面 双引号里面的值 和 class=后面 双引号里面的值

数据录入

为了能及时跟进 各个厂家的 页面的改动 ,
我们将数据统一后台录入为标准,前台调用接口的形式,来操作厂家 页面元素的去除

后台录入如下数据

id 以#开头,class以.开头
录入的数据 以 英文的 , 作为分割

淘宝客户端广告

在测试数据的时候 , 我们发现 淘宝 头部 的客户端 广告 的 idclass 都是 随机haxi算法生成的。
也就是后台没办法录入这样的数据,因为你录了这次的 idclass 值 页面刷新一下 就又变了,
所以我们只好 在脚本里面写死,根据我们的算法模糊匹配 idclass

如果您在寻找 浮动广告元素的 idclass 的时候,
发现 是 数据和 字母组合的,并且没有意义的组合,请告知我 @julian 。

前端实现方案

了解了前面一些相关概念之后,接下来我们来看实际解决方案。
在整个手淘团队,我们有一个名叫 lib-flexible的库,而这个库就是用来解决H5页面终端适配的。

lib-flexible是什么?

lib-flexible 是一个制作H5适配的开源库。

当然你可以直接使用阿里CDN:

1
<script src="http://g.tbcdn.cn/mtb/lib-flexible/{{version}}/??flexible_css.js,flexible.js"></script>

将代码中的 换成对应的版本号0.3.4。

使用方法

lib-flexible库的使用方法非常的简单,只需要在Web页面的 <head></head> 中添加对应的flexible_css.js,flexible.js文件:

出入江湖

曾几何时为了兼容IE低版本浏览器而头痛,以为到Mobile时代可以跟这些麻烦说拜拜。
可没想到到了移动时代,为了处理各终端的适配而乱了手脚。
对于混迹各社区的偶,时常发现大家拿手机淘宝的H5页面做讨论——手淘的H5页面是如何实现多终端的适配?

那么趁此Amfe阿里无线前端团队双11技术连载之际,用一个实战案例来告诉大家,
手淘的H5页面是如何实现多终端适配的,希望这篇文章对大家在Mobile的世界中能过得更轻松。

目标

拿一个双11的Mobile页面来做案例,比如你实现一个类似下图的一个H5页面:

目标很清晰,就是做一个这样的H5页面。

demo

请用手机扫下面的二维码

痛点

虽然H5的页面与PC的Web页面相比简单了不少,但让我们头痛的事情是要想尽办法让页面能适配众多不同的终端设备。
看看下图你就会知道,这是多么痛苦的一件事情:

点击这里查看更多终端设备的参数。

再来看看手淘H5要适配的终端设备数据:

看到这些数据,是否死的心都有了,或者说为此捏了一把汗出来

手淘团队适配协作模式

早期移动端开发,对于终端设备适配问题只属于Android系列,只不过很多设计师常常忽略Android适配问题,只出一套iOS平台设计稿。
但随着iPhone6,iPhone6+的出现,从此终端适配问题不再是Android系列了,也从这个时候让移动端适配全面进入到“杂屏”时代。

上图来自于 paintcodeapp.com

为了应对这多么的终端设备,设计师和前端开发之间又应该采用什么协作模式?或许大家对此也非常感兴趣。

而整个手淘设计师和前端开发的适配协作基本思路是:

  • 选择一种尺寸作为设计和开发基准
  • 定义一套适配规则,自动适配剩下的两种尺寸(其实不仅这两种,你懂的)
  • 特殊适配效果给出设计效果

还是上一张图吧,因为一图胜过千言万语:

在此也不做更多的阐述。

在手淘的设计师和前端开发协作过程中:

  • 手淘设计师常选择iPhone6作为基准设计尺寸,
  • 交付给前端的设计尺寸是按750px * 1334px为准(高度会随着内容多少而改变)。
  • 前端开发人员通过一套适配规则自动适配到其他的尺寸。

根据上面所说的,设计师给我们的设计图是一个750px * 1600px的页面:

前端开发完成终端适配方案

拿到设计师给的设计图之后,剩下的事情是前端开发人员的事了。
而手淘经过多年的摸索和实战,总结了一套移动端适配的方案—— flexible方案。

这种方案具体在实际开发中如何使用,暂时先卖个关子,在继续详细的开发实施之前,我们要先了解一些基本概念。

一些基本概念

在进行具体实战之前,首先得了解下面这些基本概念(术语):

视窗 viewport

简单的理解,viewport是严格等于浏览器的窗口。在桌面浏览器中,viewport就是浏览器窗口的宽度高度。但在移动端设备上就有点复杂。

移动端的viewport太窄,为了能更好为CSS布局服务,所以提供了两个viewport:虚拟的viewportvisualviewport和布局的viewportlayoutviewport。

George Cummins在Stack Overflow上对这两个基本概念做了详细的解释

而事实上viewport是一个很复杂的知识点,上面的简单描述可能无法帮助你更好的理解viewport,而你又想对此做更深的了解,可以阅读PPK写的相关教程。

### 物理像素(physical pixel)

物理像素又被称为设备像素,他是显示设备中一个最微小的物理部件。
每个像素可以根据操作系统设置自己的颜色和亮度。
正是这些设备像素的微小距离欺骗了我们肉眼看到的图像效果。

设备独立像素(density-independent pixel)

设备独立像素也称为密度无关像素,可以认为是计算机坐标系统中的一个点,这个点代表一个可以由程序使用的虚拟像素(比如说CSS像素),然后由相关系统转换为物理像素。

CSS像素

CSS像素是一个抽像的单位,主要使用在浏览器上,用来精确度量Web页面上的内容。
一般情况之下,CSS像素称为与设备无关的像素(device-independent pixel),简称DIPs。

### 屏幕密度

屏幕密度是指一个设备表面上存在的像素数量,它通常以每英寸有多少像素来计算(PPI)

设备像素比(device pixel ratio)

设备像素比简称为dpr,其定义了物理像素和设备独立像素的对应关系。它的值可以按下面的公式计算得到:

设备像素比 = 物理像素 / 设备独立像素

在JavaScript中,可以通过 window.devicePixelRatio获取到当前设备的dpr
而在CSS中,可以通过 -webkit-device-pixel-ratio-webkit-min-device-pixel-ratio-webkit-max-device-pixel-ratio进行媒体查询,
对不同dpr的设备,做一些样式适配(这里只针对webkit内核的浏览器和webview)。

dip或dp,(device independent pixels,设备独立像素)与屏幕密度有关。
dip可以用来辅助区分视网膜设备还是非视网膜设备。

缩合上述的几个概念,用一张图来解释:

众所周知,iPhone6的设备宽度和高度为 375pt * 667pt,可以理解为设备的独立像素;而其dpr为2,根据上面公式,我们可以很轻松得知其物理像素为750pt * 1334pt

如下图所示,某元素的CSS样式:

1
2
width: 2px;
height: 2px

在不同的屏幕上,CSS像素所呈现的物理尺寸是一致的,而不同的是CSS像素所对应的物理像素具数是不一致的。
在普通屏幕下1个CSS像素对应1个物理像素,而在Retina屏幕下,1个CSS像素对应的却是4个物理像素。

有关于更多的介绍可以点击这里详细了解。

看到这里,你能感觉到,在移动端时代屏幕适配除了Layout之外,还要考虑到图片的适配,
因为其直接影响到页面显示质量,对于如何实现图片适配,再此不做过多详细阐述。这里盗用了@南宮瑞揚根据mir.aculo.us翻译的一张信息图:

meta标签

<meta> 标签有很多种,而这里要着重说的是viewport的meta标签,
其主要用来告诉浏览器如何规范的渲染Web页面,而你则需要告诉它视窗有多大。
在开发移动端页面,我们需要设置meta标签如下:

1
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

代码以显示网页的屏幕宽度定义了视窗宽度。网页的比例和最大比例被设置为100%。

留个悬念,因为后面的解决方案中需要重度依赖meta标签。

CSS单位rem

W3C规范中是这样描述rem的:

font size of the root element.

简单的理解,rem 就是相对于根元素 <html> 的font-size来做计算。
而我们的方案中使用rem单位,是能轻易的根据 <html> 的font-size计算出元素的盒模型大小。
而这个特色对我们来说是特别的有益处。

本文将记录一些常用gem命令,以备不时之需(每次都查还烦人)

更换淘宝镜像

由于国内网络原因(你懂的),导致 rubygems.org 存放在 Amazon S3 上面的资源文件间歇性连接失败。
这里要更换默认镜像为淘宝的镜像。

1
2
3
4
5
6
7
gem sources --remove https://rubygems.org/
gem sources -a https://ruby.taobao.org/
gem sources -l
*** CURRENT SOURCES ***

https://ruby.taobao.org
# 请确保只有 ruby.taobao.org

常用命令

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
gem -v # 查看RubyGems软件的版本

gem help #显示RubyGem使用帮助
gem help example #列出RubyGem命令一些使用范例

gem install [gemname] # 安装指定gem包,程序先从本机查找gem包并安装,如果本地没有,则从远程gem安装。
gem install -l [gemname] # 仅从本机安装gem包
gem install -r [gemname] # 仅从远程安装gem包
gem install [gemname] --version=[ver] # 安装指定版本的gem包

gem uninstall [gemname] # 删除指定的gem包,注意此命令将删除所有已安装的版本
gem uninstall [gemname] --version=[ver] # 删除某指定版本gem

gem update --system # 更新升级RubyGems软件自身
gem update [gemname] #更新所有|指定已安装的gem包

gem list # 查看本机已安装的所有gem包 #显示RubyGem使用帮助

更多文档

查看远程仓库

git remote -v

1
2
3
$ git remote -v
origin git@github.com:zanjs/ippt.git (fetch)
origin git@github.com:zanjs/ippt.git (push)

从上面的结果可以看出,远程仓库有一个 origin

## 从远程获取最新版本到本地

git fetch origin master

1
2
3
4
5
6
7
8
$ git fetch origin master
remote: Counting objects: 17, done.
remote: Compressing objects: 100% (7/7), done.
remote: Total 17 (delta 11), reused 15 (delta 9), pack-reused 0
Unpacking objects: 100% (17/17), done.
From github.com:zanjs/ippt
* branch master -> FETCH_HEAD
7c6a6db..8dafd85 master -> origin/master

$ git fetch origin master 这句的意思是:
从远程的origin仓库的master分支下载代码到本地的origin master

比较本地的仓库和远程参考的区别

git log -p master.. origin/master

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
$ git log -p master.. origin/master
commit 8dafd85f249f1d20275052a402657a746a51111c
Author: zanjs <root@zanjs.com>
Date: Sat Dec 26 13:37:42 2015 +0800

ippt By gitpush

diff --git a/package.json b/package.json
index 21aac2b..43523a8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "ippt",
- "version": "0.0.7",
+ "version": "0.0.8",
"description": "ppt,nodejs,javascript",
"main": "./bin/ippt",
"bin": { "ppt": "./bin/ippt" },

commit 8ea5978c749b71eace036f6ba05424e24b947e6b
Author: zanjs <root@zanjs.com>
Date: Sat Dec 26 13:36:02 2015 +0800

:

我的本地代码和远程代码不相同,由于是在2台电脑上做了提交

把远程下载下来的代码合并到本地仓库,远程的和本地的合并

git merge origin/master

1
2
3
4
5
6
7
8
9
10
11
12
13
Administrator@WIN-9PH4ISN44NM MINGW64 /e/zan/coding/panli/ppt/ippt (master)
$ git merge origin/master
Updating 7c6a6db..8dafd85
Fast-forward
assets/js/nodeppt.js | 4 ++--
bin/{ippt.js => ippt} | 0
lib/server.js | 12 ++++++------
package.json | 8 ++++----
template/markdown.ejs | 2 +-
up.md | 8 ++++++++
6 files changed, 21 insertions(+), 13 deletions(-)
rename bin/{ippt.js => ippt} (100%)
create mode 100644 up.md

由于远程的是最新的 所以需要更新我本地的代码