Damon小站

理解REST

Jul 17, 2016 - 1 minute read - Comments

REST(Representational State Transfer:表述性状态传递),由Roy Fielding在他2000年时的 博士论文中引入和定义的。 REST是为分布式定义的一个架构形式,它不是一个标准,但有一些限制:如状态,client/server关系,统一的接口形式。 REST通常用HTTP实现。 REST原则 资源 可以通过结构化的URI方便导出 表述性 通过JSON或者XML来表述数据对象和属性 消息 显式使用HTTP方法(GET,POST,PUT,DELETE) 无状态 client和server之间的交互无上下文,状态依赖和扩展是可以扩展,client不保存session状态。 HTTP方法 使用HTTP方法匹配CRUD(create, retrieve, update, delete)操作。 GET 获取信息,GET请求必须安全并且幂等,即无论同一个参数请求多少次,都返回同样的结果。 可以有副作用,但用户并不关注这个副作用,所以不能运行系统中至关重要的操作。 请求可以是部分或者条件的。 示例为用ID为1的获取地址: GET /addresses/1 POST 通常POST用来创建一个新的实体,但不用来更新一个实体。 创建新的地址 POST /addresses PUT 在URI中存储实体,可以用来创建一个新的实体或者更新一个实体。一个PUT请求是幂等的。 幂等是PUT动作和POST请求之间的最大差异 修改ID为1的地址 PUT /addresses/1 注意:PUT替换原来已经存在的实体,如果仅提供数据元素的子集,REST将更新为空或者null。 PATCH 更新URI中的指定字段,PATCH是幂等的。 PATCH /addresses/1 DELETE 移除资源,但不需要立即移除资源,可以异步处理或者很长时间的请求。 DELETE /addresses/1 HTTP状态码 HTTP请求结果的的状态显示 1xx - 信息 2xx - 成功 3xx - 跳转 4xx - client错误 5xx - server错误 Media类型 HTTP请求头中的Accept和Content-Type可以用来描述HTTP中发送或者请求的内容。当client 设置Accept为 application/json 时,希望请求可以返回一个JSON信息。当client设置

异步编程的Promise模式

Jul 16, 2016 - 1 minute read - Comments

promise 代表了一个种可能会长时间运行而且不一定必须完成的操作结果。这种模式不会阻塞和等待长时间的操作完成, 而是返回了一个代表承诺的(promised)结果的对象。 promise的模式在任何时刻都处于以下三种状态之一:未完成(unfulfilled),已完成(resolved)和拒绝(rejected)。 promise对象上的then方法负责添加针对已完成和拒绝状态下的处理函数。then方法会返回一个promise对象,已便形成 promise管道(pipeline模式),这种返回promise对象的方法能够支持开发人员把异步操作串联起来。 then(resolvedHandler, rejectedHandler),resolvedHandler回调函数在promise对象进入完成状态时会触发, 并传递结果;rejectedHandler函数会在拒绝状态下调用。 promise对象需要两个方法,用来执行从未完成到已完成和从未完成到拒绝的状态转变。 Promise.prototype.resolve = function(value){ // move from unfulfilled to resolved } Promise.prototype.reject = function(error){ // move from unfulfilled to rejected } 当有多个Ajax请求的并发协作的时候,需要when来存储准备调用的promise对象,一旦某个promise从未完成状态 转化为完成或者拒绝状态,then方法里对应的处理函数就会被调用。 Promise.when = function(promised1, promised2, ...){ // handle promises arguments and queue each. } (为何不是在prototype上设置when呢?) when会有多变种,when.some(), when.all(), when.any()等。 promise使用,必然会使用到pipeline模式,关于pipeline的好处,参考Pipe 之美 本文从 http://www.infoq.com/cn/news/2011/09/js-promise 摘要下来

如何进行技术选型

Jul 11, 2016 - 1 minute read - Comments

对于开发而言,技术选型是重中之重,然而实际经历过的选型大概有这么几种 我就只知道这种技术,没得选 我听过某个很热门,就选那种 网上搜到某个问题可以用某个技术解决,就这了。 经过仔细研究调查,然后选择某种 刚毕业的时候在小公司时,基本上就只会第一二三种方式来进行选型,熬过几年,有人提点后,才会慢慢懂得怎么来选型。 对于个人型的项目,第一二种只是个人行为,无所谓。但对于公司项目,如果还是这么选型的话,就只能呵呵了。 对于语言的选型,通常需要考虑这么几个事情: 对于初创公司,这么语言的开发效率快不快 对于成熟的公司,这门语言的招人容易不容易 这门语言的第三方周边库丰富不丰富 团队中的成员是否有足够的能力驾驭这门语言 这门语言可以快速解决什么样的问题 对于开源库(开源产品)的选型,通常需要考虑下面几个问题: 库是否足够稳定 库是否持久维护 库是否按照开源规范维护 如果库中出现问题,是否能够修正或者快速找人修正 库的版权是否合适 库的周边是否丰富(如文档,如插件)

docker compose start

Jul 7, 2016 - 1 minute read - Comments

docker启动时不同镜像之间的链接的处理是比较麻烦的,所以官方目前有一个docker-compose用来做这些事情,官方给的例子是这样的。 构建一个Web应用 官方使用Python下的Flask框架构建的应用,创建了一个app.py的文件: from flask import Flask from redis import redis app = Flask(__name__) redis = Redis(host='redis', port=6379) @app.route('/') def hello(): redis.incr('hits') return "Hello World! I have been seen %s times" % redis.get('hits') if __name__ == '__main__': app.run(host='0.0.0.0', debug=True) 创建一个requirements.txt的文件(给pip安装程序用) flask redis 创建一个Docker镜像 首先构建一个Dockerfile文件 FROM Python:2.7 ADD . /code WORKDIR /code RUN pip install -r requirements.txt CMD python app.py 然后构建镜像 docker build -t web . 定义服务 通过docker-compose.yml定义服务: version: '2' services: web: build: .

Go中使用uint64遇到的问题

Jul 6, 2016 - 1 minute read - Comments

因为设计的缘故,我们内部系统使用了不少了uint64,同时也带来了很多问题: 在Go的mysql实现中,对于uint64的转换,是分两部分的,具体代码(https://github.com/go-sql-driver/mysql/blob/master/packets.go#1137): case fieldTypeLongLong: if rows.columns[i].flags&flagUnsigned != 0 { val := binary.LittleEndian.Uint64(data[pos : pos+8]) if val > math.MaxInt64 { dest[i] = uint64ToString(val) } else { dest[i] = int64(val) } } else { dest[i] = int64(binary.LittleEndian.Uint64(data[pos : pos+8])) } pos += 8 continue 上面可以看到,对于uint64部分,是通过两个不同的数据类型来处理的。当将从数据库获取获取的所有数据以map[string]interface{}形式返回时,map的value值类型就有可能是int64和uint64,这对于强类型的Go而言,无疑是一个麻烦的事情,得自己做断言判断,常常会因为不小心遗漏而导致异常(不易发现)。 在将Go中的uint64返回给前端的时候,由于JavaScript不支持64位的整型数值,前端有可能会准确(值比较小,可以用32位的int表示),也有可能失败,这也是一个麻烦的事情。所以为了统一解决,需要将uint64的数据,转换为字符串方式,然后转递给前端处理。 后台传递给前端需要将uint64转换为字符串,就需要在返回前去小心处理uint64的值(这通常也是一个麻烦的事情)。

golang routine id

Jul 5, 2016 - 1 minute read - Comments

在Go中,系统是不提供goroutine的id给外界的,丫的认为这事情不应该提供给用户来使用。 可有时候,实在是觉得这个东西必须得有呀,比方说后台开了个goroutine进行http请求的处理,这个免不了要打个日志什么的, 当并发量稍微大点的时候,就会发现这些信息的输出就交叉错乱在一起了。怎么区分。 一种方案是在http请求的时候,生成一个context的东西,里面有个值来表示是这个goroutine,然后打日志的时候将这个值输出来。 这种方案的问题是:你得将这个context显示的一路传递下去,显然这个这很多时候会很痛苦。 另一种方案是如果系统能够提供一个标识来表明这个goroutine的信息,那么就不必要这么麻烦了。所以考虑之后,决定采用这种获取系统的goroutine id的方案。 go1.6中具体方法是在src/runtime/proc.go尾部添加 // export Goid func Goid() int64 { _g_ := getg() return _g_.goid } 重新编译生成对应的go编译器(最好用go1.4来编译,省事),然后就可以在代码中用runtime.Goid获取到对应的id了。 线上跑了几个月,没有出现过异常,所以还是比较稳定的。