之前也说了,开始玩儿nodejs,然后拿cheater下手。做得差不多了,总结一下。会有几篇单独的文章,省得看起来乱。
nodejs的基本思想就是异步,这对传统编程模型是彻底的颠覆。刚开始很不习惯,死得很惨,程序怎么都不按我想的跑。一个简单的例子就是http的request,调用不会等待response而是立即返回,然后通过回调函数处理response。
之前也说了,开始玩儿nodejs,然后拿cheater下手。做得差不多了,总结一下。会有几篇单独的文章,省得看起来乱。
nodejs的基本思想就是异步,这对传统编程模型是彻底的颠覆。刚开始很不习惯,死得很惨,程序怎么都不按我想的跑。一个简单的例子就是http的request,调用不会等待response而是立即返回,然后通过回调函数处理response。
不知道npm是什么的同学,自己google,提示一下,跟node相关。
npm安装分为两种,local和global,有什么区别这里说得已经很详细了:http://blog.nodejs.org/2011/03/23/npm-1-0-global-vs-local-installation/,我也就不再废话了。
只是有些东西还要解释一下。
刚装好npm的时候,我惊异地发现它所有的安装目录全是777的权限,表示不理解(而且terminal里面看过去,非常不好看),手工改成755。这样带来的问题是如果做global安装的话,普通用户则无法安装;ok没问题,我可以sudo来搞,但是sudo之后新的问题又来了,~/.npm是做cache用的,sudo安装的话这里面东西可都属于root了。这个设计比较土,理想的方案是local安装,~/.npm作为cache,global安装,cache在npm自己的安装路径下。
还有local这种安装方式看起来隔离性挺好,但是对版本管理工具可不怎么友好,不知道有没有办法。
我是意思是js里压根儿就没有object,全是浮云;其实根本就是function。
越看越糊涂,这语言设计得真是够可以的。都说是OO,其实就是个屁,所有东西都是用function模拟的。没有任何东西能跟传统意义上的OO对应起来,然后就说这门语言比较深奥,受过传统程序设计教育的人不容易理解。操蛋也不能操成这样吧?如果你说我就是不支持OO,OO算个屁,那也好很多。
只是发发牢骚,不能这么让人忽悠了,但是该学还是要好好学,既然它这么设计了,就咬牙跟进吧。
??
this在js里设计得还真是够复杂,或者确切地说根本就是设计错了(这不是我说的,是写那本the good parts的老大说的)。
一个例子:
1 2 3 4 5 6 7 | myObject.double = function () { var helper = function () { this.value = add(this.value, this.value); }; helper(); }; |
这个方法要做的事情很简单,就是把自己的value属性double一下。一切看起来都很完美,直到真正跑起来,你才会发现报错说value没定义。
原因在于那个内部匿名函数里的this并不是myObject,而是这个函数本身!诡异得很。
解决起来倒是简单:
1 2 3 4 5 6 7 8 9 | myObject.double = function () { var that = this; var helper = function () { that.value = add(that.value, that.value); }; helper(); }; |
习惯上大家都用that。怪不得之前总是看到that这that那的,还以为是js的保留字。
我不是做CM的,但是家里有两台工作机器、一台二奶机,所以弄个Nexus还是有点意义的。
过程相当容易。
1. 这里下:http://nexus.sonatype.org/
2. 解包
3. bin/jsw/<arch>/nexus start(Windows底下不是这个,我不想写,自己研究吧)
4. http://<server>:8081/nexus
5. 在Repositories里面加自己需要的repository,注意三种类型:hosted、proxy、virtual;鼠标移动到问号上有提示,这里就不多说了
6. 修改$HOME/.m2/settings.xml
1 2 3 4 5 6 | <mirror> <id>id</id> <mirrorOf>*</mirrorOf> <name>xxx</name> <url>http://<server>:8081/nexus/content/groups/public/</url> </mirror> |
这里把所有的repository都mirror到Nexus去。
7. 还有复杂的权限控制,我暂时用不到,以后需要再说吧。
node.js是一个server端js的运行时。
想研究一下,就拿cheater来练手。(注:cheater是在公司里对付cc zone的实现自动登录的小工具)
首先想到的是用来做管理、监控的socket端口。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | var net = require('net'); var server = net.createServer(function (client) { // 有client连上来的时候调用此回调函数 client.setEncoding('ascii'); // 设置编码,否则下面的data默认使用Buffer client.write('> '); client.on('data', function (data) { // client发数据过来,触发'data'事件,然后调用此回调函数 switch (data.trim()) { case 'status': client.write('heartbeating...\r\n'); client.write('> '); break; case 'quit': client.end(); // 关掉client break; case 'shutdown': client.end(); server.close(); // 关掉server break; default: client.write('> '); break; } }); }); server.listen(44050, 'localhost'); |
值得注意的是,这里只有一个线程,所有异步的事情都靠事件驱动。这也就是node.js一个最核心的思想:用单个线程充分压榨CPU资源,能异步的全都异步了。
刚开始玩儿,哪里不对的,请多指正。顺便帮cnodejs做个广告。
就忙着调性能了……
跟所有Lift的feature一样,支持REST也是非常非常得简单。
Mixin这个trait:
Boot.scala里面加上:
1 | LiftRules.dispatch.append(AdminAPI) |
如果不需要创建session(不创建著名的S对象),还可以:
1 | LiftRules.statelessDispatchTable.append(AdminAPI) |
然后就是URL匹配:
1 2 3 4 5 6 | serve { case "api" :: "add" :: Nil JsonGet _ => add case "api" :: "delete" :: Nil JsonGet _ => delete case "api" :: "edit" :: Nil JsonGet _ => edit case "api" :: "get" :: Nil JsonGet _ => get } |
以上都是GET的JSON接口。JsonGet会检查HTTP头里面的Accept以确认client是否支持JSON,这里需要注意的是“*/*”表示所有都接受(这个应该已经在2.3里面被修复掉了);当然如果Accept里面不支持JSON,JsonGet还会去查询URL是否是.json结尾。
具体解释一下上面的例子。
对于URL为 http://server/api/add.json 的请求,第一条匹配规则命中,最后那个“_”是Req,然后调用add方法,add的返回值需要是LiftResponse类型;其实LiftReponse是个啥都不干的trait,有很多实现,JsonResponse、XmlResponse等等,总之几乎不用特别在意,Lift里面能作为response返回给client的都能用。
其他的匹配类似处理。
给个add方法的实现:
1 2 3 4 5 6 7 8 9 10 11 12 | private def add = { val linkId = param(ShortenedUrl.originUrl.name).map(x => { shortenedUrl.find(ShortenedUrl.originUrl.name -> x).map(_.linkId.value) or { val tmp = (DependencyFactory.inject[NextIdGenerator].open_! !? 'id).toString shortenedUrl.createRecord.linkId(tmp).originUrl(x).shortUrl(Props.get(Site).open_! + "/" + tmp).date(new Date). ip(containerRequest.map(_.remoteAddress).toString).clickCount(0).save Full(tmp) } }) (StatusField -> linkId.map(_.map(x => SuccessStatus)).openOr(Full(FailedStatus)).openOr(FailedStatus)) ~ (ShortenedUrl.linkId.name -> linkId.openOr(Full("")).openOr("")) } |
返回一个JSON对象{status: “successful”, linkId: “1″}。
Lift利用Scala对DSL的支持把JSON整得很舒服,几乎跟js原生的用起来没区别:
1 2 3 | ("name" -> "honnix") ~ ("address" -> "somewhere") ~ ("phone" -> List("111", "222", "333")) |
等价于:
1 2 3 | {name: "honnix", address: "somewhere", phone: ["111", "222", "333"]} |
具爽吧?