dig deeper, do different

2016-09-30
乐动力“网络不给力”问题的处理

MX5上的乐动力 App 很早以前就不能登录了,各种途径都是提示“网络不给力”,等了大半年看他们是否会修正这个问题,但是每次版本更新后都试了,问题依旧存在。而且,无论是官网还是 App或是微博客服,都没有提供相关的说明该如何操作。
为了不丢失数据,只好自己动手了。

进入 Flyme 5 的访客系统,安装微信和乐动力 App,测试登录正常,之前的数据也能正常同步下来。

第一步,祭出 Charles 看看都干了啥

启动 Charles,然后在手机上设置代理,进行登录,发现一个正常的登录主要做了几个操作:

  1. adduser,发送一个 pc 串,返回一个临时的 id
  2. authbywechat,登录请求,url参数 uid 为之前请求的临时 id,返回用户 id
  3. getinfo,获得用户相关信息,包括头像 url
  4. updatewechatinfo,更新数据
  5. updateinfo,更新数据

第二步,进入正常的系统,看看无法登录的版本都做了些什么

  1. authbywechat,url参数 uid 为残留的用户 id,返回 {“errorCode”: -10001, “ret”: “auth fail”}

返回错误后就没有后续请求了。

现在看来就是验证的时候的 uid 的问题。查看反编译后的代码的时候发现,登录成功后这个 uid 是会被覆盖的。这样的话,给 App 一些正常的数据,让他先登录成功一次,以后理论上就不会有问题了。

如果是 root 的设备,直接把 SharedPreferences 中的 uid 的值改为0,App 就会进入 adduser 的流程,这样会比较简单。我不想 root 这个设备,所以写了些代码来模拟登录的流程。

第三部,拦截请求,修改数据

把正常登录的数据保存下来,在拦截到请求后把这些数据返回给 App。可能这部分也可以在 Charles 中完成,不过我修改了 hosts 文件,然后直接写了些 php 代码:
hosts 文件:

1
127.0.0.1 walk.ledongli.cn

路由部分:

1
2
3
4
Route::post('/v2/rest/users/authbywechat', 'MsgController@handleAuthWeChat');
Route::post('/v2/rest/users/getinfo', 'MsgController@handleGetInfo');
Route::post('/v2/rest/users/updatewechatinfo', 'MsgController@handleUpdateWeChatInfo');
Route::post('/v2/rest/users/updateinfo', 'MsgController@handleUpdateInfo');

响应部分(uid 和部分返回值删除了):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public function handleUpdateWeChatInfo(Request $request) {
return response()->json(["errorCode" => 0, "ret" => null]);
}
public function handleUpdateInfo(Request $request) {
return response()->json(["errorCode" => 0, "ret" => null]);
}
public function handleAuthWeChat(Request $request) {
return response()->json(["errorCode" => 0, "ret" => ["uid" => xxxxxxxxxx]]);
}
public function handleGetInfo(Request $request) {
return response()->json(["errorCode" => 0, "ret" => ["target" => , "weight" => "", "gender" => "m", "checkined" => , "checkin_mcount" => , "birthdate" => "", "height" => "", "is_wechat" => true, "avatar" => "", "is_qq" => false, "is_sina" => false, "nickname" => "", "email" => "", "is_email" => false]]);
}

登录进入 App 之后,把 hosts 文件还原,去掉手机上 wifi 的代理,再在 App 中点击立即备份数据,可以看到开始正常备份了。

最后

  • 之所以出现这个问题,是因为残留的 uid 去请求登录的时候会导致失败。可能的原因大概是某一个版本的登录逻辑改变了,但是没有处理好老版本的兼容性。其实哪怕多加一个按钮能重置一下用于登录的临时 id 也好啊。
  • 同步的时候也出现了问题,同步一两条数据后就会卡住不动,不会自动重新开始,需要用户反复的进行操作才能把所有的数据同步完。
  • 退出登录的时候,居然真的把用户的数据删除了。

综合来看,乐动力这个 App 在这部分上设计得是比较烂的,可能只是一个临时的外包产品的品质。

Read More

2016-07-30
React with Node.js in Webstorm

软件环境:

软件 版本
OSX 10.11.6
WebStorm 2016.2
Node.js 6.3.1
React 15.3.1

Node.js 是通过 nvm 安装的最新版本。国内的网络环境,想通过 WebStorm 直接创建工程是做不到的,只能通过命令行,使用淘宝的镜像。

安装 express

1
2
3
4
5
cd reactStudy
npm install --registry=https://registry.npm.taobao.org -g express-generator
express -e -css sass reactStudy
cd reactStudy
npm install --registry=https://registry.npm.taobao.org

安装 react

安装 react、react-dom、babel、browserify、watchify 等模块。package.json 文件的内容如下:

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
{
"name": "taskmgr",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"babel-cli": "^6.11.4",
"babel-preset-es2015": "^6.9.0",
"babel-preset-react": "^6.11.1",
"babelify": "^7.3.0",
"body-parser": "~1.15.1",
"cookie-parser": "~1.4.3",
"debug": "~2.2.0",
"ejs": "~2.4.1",
"express": "~4.13.4",
"express-session": "^1.14.0",
"morgan": "~1.7.0",
"mysql": "^2.11.1",
"node-sass-middleware": "0.8.0",
"passport": "^0.3.2",
"react": "^15.3.0",
"react-dom": "^15.3.0",
"serve-favicon": "~2.3.0"
},
"devDependencies": {
"browserify": "^13.1.0",
"watchify": "^3.7.0"
}
}

创建文件

在 views 目录下创建一个文件作为主文件:main.js。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var React = require('react');
var ReactDOM = require('react-dom');
var Main = React.createClass({
render: function () {
return <div>Hello william</div>
}
});
ReactDOM.render(
<Main />,
document.getElementById('content')
);

也可以使用 ES2015的方式来写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import React from "react"
import ReactDOM from "react-dom"
class App extends React.Component{
constructor(props) {
super(props)
}
render() {
return <div>Hello World!</div>
}
}
ReactDOM.render(<App/>, document.getElementById('content'));

配置babel

WebStorm->Preferences…->Tools->File Watchers下添加Babel。以下字段需要注意修改:

Field Value 说明
Name Babel 这里不要修改,不然还会提示添加 Babel Watcher
File type javascript 也可以选其他类型,只要和你自己的文件匹配
Program $ProjectFileDir$/node_modules/browserify/bin/cmd.js
Arguments -t [ babelify –presets [ es2015 react ] ] ./views/main.js -o public/javascripts/index.bundle.js 如果要调试,需要加上 -d 参数

index.ejs文件的下方添加

1
<script type="text/javascript" src="/javascripts/index.bundle.js"></script>

最后的效果:

1
2
3
4
5
6
<body>
<div id="content"></div>
<script type="text/javascript" src="/javascripts/index.bundle.js"></script>
</body>

因为对 Babel 和 browserify 不熟悉,所以这一段是花时间最多的地方。开始的时候因为用了 jsx 扩展名,在文件头的注释中有@jsx,render 函数翻译出来的代码会带上 file 函数而不是React.createElement,导致错误。后来重启 WebStorm 就好了。

结束.

Read More

2016-04-18
Node.js from scratch

使用 webstorm,从创建一个空白的工程开始构建一个 Node.js 的websocket服务器。

  1. 创建空白工程
  2. 添加一个 js 文件,比如 main.js
  3. 添加一个 package.json 文件
  4. 在控制台中进入工程的根目录,使用命令npm install --save ws添加websocket模块。使用--save参数会把模块的依赖直接添加到 package.json 文件中。
  5. 编辑webstorm 的 Run/Debug配置,新建一个 Node.js 的配置,在 JavaScript file:这一栏里面写上main.js
  6. 在 main.js 中填入如下代码:
1
2
3
4
5
6
7
8
9
10
var WebSocketServer = require('ws').Server;
var wss = new WebSocketServer({port: 8280});
wss.on('connection', function connection(ws) {
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
ws.send('something');
});

至此,一个服务器就搭建好了。

注意点:
在 webstorm 中,可能会提示Unresolved function or method require(),这是因为没有开启Node.js Core library。在 webstorm 的Preferences->Languages & Frameworks->Node.js and NPM下开启就可以了。

Read More

2015-09-20
phpStorm remote debug with xdebug

因为使用了 docker 进行了环境隔离,所以需要对 phpStorm 进行远程调试的配置。

网上有一些教程,不是太复杂就是已经过时。经过摸索,一下是完整的配置流程。

版本: ubuntu 14.04 LTS, phpStorm 9, php5-fpm

首先是服务器端的设置:

  1. 安装xdebug

    1
    apt-get install php5-xdebug
  2. 配置 xdebug

    1
    vim /etc/php5/fpm/conf.d/20-xdebug.ini

加入:

1
2
3
4
5
zend_extension=xdebug.so
xdebug.remote_mode="req"
xdebug.idekey="PHPSTORM"
xdebug.remote_enable=1
xdebug.remote_connect_back=1

上面的设置也可以直接放在 php.ini 中。

接下来进行客户端的设置:

  1. 点击phpStorm菜单Run -> Start Listening for PHP Debug Connections
  2. 设置断点
  3. 安装 xdebug-helper Chrome 浏览器插件
  4. 打开要调试的网页,激活地址栏的 xdebug-helper
  5. 如果一切都设置正确,在 phpStorm 会弹出对话框进行文件映射等设置。

这样就可以了。

PS:
如果在 phpStorm 中创建 Remote debug 配置,也是可以收到 debug 断点的。

如果是apache2,xdebug 的默认配置文件会出现在 /etc/php5modes-available/xdebug.ini

UPDATE
如果web 服务器是在Docker for Mac下使用的话,xdebug.remote_connect_back=1会不起作用,因为这里的 docker container 接受到的 ip 都是来自172.17.0.1,所以需要显式的指定 ip 和端口:

1
2
3
4
5
6
7
zend_extension=xdebug.so
xdebug.remote_mode="req"
xdebug.idekey="PHPSTORM"
xdebug.remote_enable=1
xdebug.remote_host="192.168.1.22"
xdebug.remote_port=9000
xdebug.remote_connect_back=0

这里的嗯Docker for Mac的版本是 v1.12,之后是否会修复这个问题,不得而知。
————2016.08.21

Read More

2015-09-13
搞定 osx 下 virtualbox 中的 docker container 访问共享文件夹的权限问题

案例是这样的:

  • 有一台 osx 系统
  • 安装了 virtualbox 虚拟机
  • 在虚拟机里面装 Linux
  • 在 Linux 里面装了 docker
  • 用 docker 装了 Ubuntu 的 image
  • 在 Ubuntu 的 container 中装了 nginx

现在把OSX 下的一个 web 开发文件夹共享给 virtualbox下的 Linux,然后在通过 docker 映射到 container 下,nginx 的 root 目录指向这个文件夹,提供 web 服务。

但是问题来了,nginx 会报错说“permission denied”。在 container 下可以很明显的看到,共享文件夹中的内容是存放在了999这个 group 中。

分析一下原因,根源在于 virtualbox 从某一个版本开始,无法修改 osx 共享目录的权限了。可以看到,在 virtualbox 下的 Linux 中,共享文件夹的权限在一个叫做vboxsf的 group 下面。

以下是解决方法:

  • 在 container 下创建一个叫做vboxsf的 group: groupadd vboxsf
  • 修改这个 group 的 id 为999:vim /etc/group
  • 把 www-data 这个用户加入到vboxsf中:usermod -a -G vboxsf www-data
  • 重启 nginx:service nginx restart
Read More