Erlang cowboy 入门参考
Erlang cowboy 入门参考
cheungmine,2014-10-28
本文翻译自:
http://ninenines.eu/docs/en/cowboy/HEAD/guide/getting_started/
我没有按原文逐句翻译。仅仅是我自己的理解,力求简单明了。本文程序在RHEL6.4上写成并运行,参考下面的文章,安装Erlang:
1 引言
Erlang不仅仅是一门语言,更是一个操作平台。Erlang开发者很少写单独的模块,而是写库和程序,然后把它们打包在一起进行发布。一个产品发布包含Erlang虚拟机和所有用来运行的程序,因此可以直接成为产品。Cowboy是Erlang编写的WebServer,提供Http,Https,WebSocket,TCP等各种高性能服务框架。本文将说明如何安装Cowboy,写第一个程序并发布。通过阅读本文,读者可以了解发布你的第一个Cowboy程序的全部内容。
2 开始第一个产品
当我们要开发一个程序(产品),我们希望用一个工程去管理它。代码构建,打包,发布等一系列行为。做Java开发使用的是Eclipse+Maven+Ant等工具。做Erlang开发可以使用Gnu Make。由于每个工具所完成的功能都类似,因此推荐使用下面这个Make模板。
https://github.com/ninenines/erlang.mk
下面开始我们的第一个Erlang工程。创建一个hello_erlang的目录,进入这个目录:
$ mkdir hello_erlang && cd hello_erlang
下载erlang.mk文件。这是erlang工程的构建脚本。关于这个脚本的细节可以在各位成为erlang专家的时候去理解。
$ wget --no-check-certificate https://raw.githubusercontent.com/ninenines/erlang.mk/master/erlang.mk
之后我们会看到目录下多了一个文件:erlang.mk。然后我们就可以生成我们的程序,同时生成发布版本(bootstrap,bootstrap-rel是target):
$ make -f erlang.mk bootstrap bootstrap-rel
现在就可以构建我们的工程,生成发布版本:
$ make
这个命令会花费较长时间执行完毕。然后启动运行产品程序:
$ ./_rel/hello_erlang_release/bin/hello_erlang_release console
输入下面的命令可以看到运行的进程,其中包括:hello_erlang_sup
。这个是我们的程序的督程(supervisor)。
(hello_erlang@127.0.0.1)1> i().
现在这个程序什么也没做,接下来我们给它添加Cowboy依赖,然后把它变成一个简单的HelloWorld程序。整个过程就是如下样子:
[root@rhel64-origin workspace]# mkdir hello_erlang [root@rhel64-origin workspace]# cd hello_erlang/ [root@rhel64-origin hello_erlang]# ls [root@rhel64-origin hello_erlang]# wget --no-check-certificate https://raw.githubusercontent.com/ninenines/erlang.mk/master/erlang.mk --2014-10-28 17:42:55-- https://raw.githubusercontent.com/ninenines/erlang.mk/master/erlang.mk Resolving raw.githubusercontent.com... 103.245.222.133 Connecting to raw.githubusercontent.com|103.245.222.133|:443... connected. WARNING: certificate common name “www.github.com” doesn’t match requested host name “raw.githubusercontent.com”. HTTP request sent, awaiting response... 200 OK Length: 20522 (20K) [text/plain] Saving to: “erlang.mk” 100%[======================================================>] 20,522 --.-K/s in 0.04s 2014-10-28 17:42:55 (473 KB/s) - “erlang.mk” saved [20522/20522] [root@rhel64-origin hello_erlang]# ls erlang.mk [root@rhel64-origin hello_erlang]# make -f erlang.mk bootstrap bootstrap-rel [root@rhel64-origin hello_erlang]# make ERLC hello_erlang_app.erl hello_erlang_sup.erl APP hello_erlang.app.src GEN distclean-relx-rel --2014-10-28 17:43:08-- https://github.com/erlware/relx/releases/download/v1.0.2/relx Resolving github.com... 192.30.252.131 Connecting to github.com|192.30.252.131|:443... connected. HTTP request sent, awaiting response... 302 Found Location: https://s3.amazonaws.com/github-cloud/releases/9900098/f6fcb596-e38d-11e3-9e8b-c953e4c1e42a?response-content-disposition=attachment%3B%20filename%3Drelx&response-content-type=application/octet-stream&AWSAccessKeyId=AKIAISTNZFOVBIJMK3TQ&Expires=1414489636&Signature=adyKnn8IPqauqWSnsXhJTc2vBio%3D [following] --2014-10-28 17:43:12-- https://s3.amazonaws.com/github-cloud/releases/9900098/f6fcb596-e38d-11e3-9e8b-c953e4c1e42a?response-content-disposition=attachment%3B%20filename%3Drelx&response-content-type=application/octet-stream&AWSAccessKeyId=AKIAISTNZFOVBIJMK3TQ&Expires=1414489636&Signature=adyKnn8IPqauqWSnsXhJTc2vBio%3D Resolving s3.amazonaws.com... 54.231.244.0 Connecting to s3.amazonaws.com|54.231.244.0|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 743699 (726K) [application/octet-stream] Saving to: “/root/workspace/hello_erlang/relx” 100%[======================================================>] 743,699 147K/s in 5.0s 2014-10-28 17:43:19 (145 KB/s) - “/root/workspace/hello_erlang/relx” saved [743699/743699] ===> Starting relx build process ... ===> Resolving OTP Applications from directories: /root/workspace/hello_erlang/ebin /usr/local/lib/erlang/lib ===> Resolving available OTP Releases from directories: /root/workspace/hello_erlang/ebin /usr/local/lib/erlang/lib ===> Resolved hello_erlang_release-1 ===> Including Erts from /usr/local/lib/erlang ===> release successfully created!
3 cowboy安装
为了使我们的hello_erlang使用cowboy,我们需要修改2个文件:Makefile和src/hello_erlang.app.src。修改后的Makefile如下:
PROJECT = hello_erlang DEPS = cowboy include erlang.mk
我们在src/hello_erlang.app.src文件中添加cowboy,这让我们的程序发布时自动将cowboy打包。有些仅仅是开发阶段的依赖不必要添加在这里(applications[...])。修改后的文件如下:
{application, hello_erlang, [ {description, "Hello Erlang!"}, {vsn, "0.1.0"}, {modules, []}, {registered, []}, {applications, [ kernel, stdlib, cowboy ]}, {mod, {hello_erlang_app, []}}, {env, []} ]}.
现在我们运行make命令,cowboy就被自动加入到产品中,当然它什么也没做。输出如下:
[root@rhel64-origin hello_erlang]# make --2014-10-28 17:53:58-- https://raw.githubusercontent.com/ninenines/erlang.mk/master/packages.v2.tsv Resolving raw.githubusercontent.com... 103.245.222.133 Connecting to raw.githubusercontent.com|103.245.222.133|:443... connected. WARNING: certificate common name “www.github.com” doesn’t match requested host name “raw.githubusercontent.com”. HTTP request sent, awaiting response... 200 OK Length: 7115 (6.9K) [text/plain] Saving to: “/root/workspace/hello_erlang/.erlang.mk.packages.v2” 100%[======================================================>] 7,115 --.-K/s in 0.001s 2014-10-28 17:54:06 (12.6 MB/s) - “/root/workspace/hello_erlang/.erlang.mk.packages.v2” saved [7115/7115] Initialized empty Git repository in /root/workspace/hello_erlang/deps/cowboy/.git/ remote: Counting objects: 7063, done. remote: Total 7063 (delta 0), reused 0 (delta 0) Receiving objects: 100% (7063/7063), 5.26 MiB | 530 KiB/s, done. Resolving deltas: 100% (4198/4198), done. make[1]: Entering directory `/root/workspace/hello_erlang/deps/cowboy' DEPPKG=$(awk 'BEGIN { FS = "\t" }; $1 == "cowlib" { print $2 " " $3 " " $4 }' /root/workspace/hello_erlang/.erlang.mk.packages.v2;) VS=$(echo $DEPPKG | cut -d " " -f1); REPO=$(echo $DEPPKG | cut -d " " -f2); COMMIT=$(echo $DEPPKG | cut -d " " -f3); if [ "$VS" = "git" ]; then git clone -n -- $REPO /root/workspace/hello_erlang/deps/cowlib; cd /root/workspace/hello_erlang/deps/cowlib && git checkout -q $COMMIT; else exit 78; fi Initialized empty Git repository in /root/workspace/hello_erlang/deps/cowlib/.git/ remote: Counting objects: 202, done. remote: Total 202 (delta 0), reused 0 (delta 0) Receiving objects: 100% (202/202), 87.64 KiB | 100 KiB/s, done. Resolving deltas: 100% (119/119), done. DEPPKG=$(awk 'BEGIN { FS = "\t" }; $1 == "ranch" { print $2 " " $3 " " $4 }' /root/workspace/hello_erlang/.erlang.mk.packages.v2;) VS=$(echo $DEPPKG | cut -d " " -f1); REPO=$(echo $DEPPKG | cut -d " " -f2); COMMIT=$(echo $DEPPKG | cut -d " " -f3); if [ "$VS" = "git" ]; then git clone -n -- $REPO /root/workspace/hello_erlang/deps/ranch; cd /root/workspace/hello_erlang/deps/ranch && git checkout -q $COMMIT; else exit 78; fi Initialized empty Git repository in /root/workspace/hello_erlang/deps/ranch/.git/ remote: Counting objects: 905, done. Receiving objects: 100% (905/905), 288.85 KiB | 170 KiB/s, done. remote: Total 905 (delta 0), reused 0 (delta 0) Resolving deltas: 100% (532/532), done. make[2]: Entering directory `/root/workspace/hello_erlang/deps/cowlib' ERLC cow_http_te.erl cow_http.erl cow_http_hd.erl cow_date.erl cow_mimetypes.erl cow_multipart.erl cow_qs.erl cow_cookie.erl cow_spdy.erl APP cowlib.app.src make[2]: Leaving directory `/root/workspace/hello_erlang/deps/cowlib' make[2]: Entering directory `/root/workspace/hello_erlang/deps/ranch' ERLC ranch_acceptors_sup.erl ranch_conns_sup.erl ranch_server.erl ranch_tcp.erl ranch.erl ranch_acceptor.erl ranch_listener_sup.erl ranch_app.erl ranch_protocol.erl ranch_ssl.erl ranch_sup.erl ranch_transport.erl APP ranch.app.src make[2]: Leaving directory `/root/workspace/hello_erlang/deps/ranch' ERLC cowboy_router.erl cowboy_rest.erl cowboy_http_handler.erl cowboy_sup.erl cowboy_websocket_handler.erl cowboy_static.erl cowboy_sub_protocol.erl cowboy_websocket.erl cowboy.erl cowboy_app.erl cowboy_handler.erl cowboy_loop_handler.erl cowboy_protocol.erl cowboy_bstr.erl cowboy_clock.erl cowboy_http.erl cowboy_spdy.erl cowboy_req.erl cowboy_middleware.erl APP cowboy.app.src make[1]: Leaving directory `/root/workspace/hello_erlang/deps/cowboy' APP hello_erlang.app.src GEN distclean-relx-rel ===> Starting relx build process ... ===> Resolving OTP Applications from directories: /root/workspace/hello_erlang/ebin /root/workspace/hello_erlang/deps /usr/local/lib/erlang/lib ===> Resolving available OTP Releases from directories: /root/workspace/hello_erlang/ebin /root/workspace/hello_erlang/deps /usr/local/lib/erlang/lib ===> Resolved hello_erlang_release-1 ===> Including Erts from /usr/local/lib/erlang ===> release successfully created!
4 监听连接
当一个客户端请求到来,我们需要根据请求内容将请求分发(dispatch)到处理器(handler)。因此我们需要一个路由表(dispatch list),cowboy根据路由表分发请求到对应的处理模块程序。然后我们让cowboy开始监听连接。
编辑Erlang程序源代码文件:src/hello_erlang_app.erl,修改start/2函数,最后的src/hello_erlang_app.erl如下:
-module(hello_erlang_app). -behaviour(application). -export([start/2]). -export([stop/1]). start(_Type, _Args) -> Dispatch = cowboy_router:compile([ {'_', [{"/", hello_handler, []}]} ]), cowboy:start_http(my_http_listener, 100, [{port, 8080}], [{env, [{dispatch, Dispatch}]}] ), hello_erlang_sup:start_link(). stop(_State) -> ok.
现在我们把根路由"/"定义到hello_handler,下面我们就需要为此写这个处理器。
5 处理请求
cowboy具有处理各种请求的特色,例如:REST,WebSocket等。这里我们使用一个简单的HTTP处理器。我们使用处理器模板生成这个处理器:
$ make new t=cowboy_http n=hello_handler
这将创建src/hello_handler.erl代码文件。打开它,修改成下面的样子(只修改了init/3):
-module(hello_handler). -behaviour(cowboy_http_handler). -export([init/3]). -export([handle/2]). -export([terminate/3]). -record(state, { }). init(_, Req, Opts) -> Req2 = cowboy_req:reply(200, [{<<"content-type">>, <<"text/plain">>}], <<"Hello Erlang!">>, Req), {ok, Req2, Opts}. handle(Req, State=#state{}) -> {ok, Req2} = cowboy_req:reply(200, Req), {ok, Req2, State}. terminate(_Reason, _Req, _State) -> ok.
6 构建并运行
$ make $ ./_rel/hello_erlang_release/bin/hello_erlang_release console
在浏览器中打开:http://your-ip-addr:8080/,显示如下:
7 总结
cowboy这个框架和nodejs很像。erlang的语法有点生疏,但是erlang比nodejs不知道强多少倍。erlang是C写的,nodejs的底层是C++,可见多数C++写的产品最后都不如C写的,这是偶然么?“一只鸟长得像鸭子,叫声像鸭子,走路也像鸭子,那它就是鸭子!”
Erlang cowboy 入门参考的更多相关文章
- Erlang cowboy 入门参考之现代Web的发展历史
Erlang cowboy 入门参考之现代Web发展史 原文: http://ninenines.eu/docs/en/cowboy/1.0/guide/modern_web/ 让我回顾一下web技术 ...
- Erlang cowboy websocket 服务器
Erlang cowboy websocket 服务器 原文见于: http://marcelog.github.io/articles/erlang_websocket_server_cowboy_ ...
- Erlang cowboy 处理不规范的客户端
Erlang cowboy 处理不规范的客户端 Cowboy 1.0 参考 本章: Dealing with broken clients 存在许多HTTP协议的实现版本.许多广泛使用的客户端,如浏览 ...
- Erlang cowboy 架构
Erlang cowboy Architecture架构 Erlang cowboy参考: http://ninenines.eu/docs/en/cowboy/1.0/guide/ 本章Archit ...
- erlang分布式入门(一)-ping pong
erlang分布式入门(一)-ping pong 测试环境和http://willvvv.iteye.com/blog/1523918 一样,192.168.0.182(centos-182)和192 ...
- Erlang cowboy 处理不规范的client
Erlang cowboy 处理不规范的client Cowboy 1.0 參考 本章: Dealing with broken clients 存在很多HTTP协议的实现版本号. 很多广泛使用的cl ...
- Erlang cowboy 处理简单的HTTP请求
Erlang cowboy 处理简单的HTTP请求 原文出自: Handling plain HTTP requests 处理请求的最简单的方式是写一个简单的HTTP处理器.它的模型参照Erlang/ ...
- Erlang cowboy routing 路由
Erlang cowboy routing 路由 本文译自: http://ninenines.eu/docs/en/cowboy/1.0/guide/routing/ Routing 默认情况下,C ...
- Erlang cowboy http request生命周期
Erlang cowboy http request生命周期 翻译自: http://ninenines.eu/docs/en/cowboy/1.0/guide/http_req_life/ requ ...
随机推荐
- UISearchController替换UISearchDisplayController
随着iOS 的升级,iOS 7的占有率更低了.Xcode 升级到Xcode 8之后,对iOS 应用支持的最低版本,iOS 7也被抛弃了.我在新项目中也是最低支持到iOS 8,因此工程里也是各种警告.首 ...
- 使用MD5SUM检查文件
有不少网站提供下载文件的同时,提供了文件的MD5SUM的值.如何检查自己下载的文件与原文件一样呢?用md5sum的-c选项. 操作如下: 1.先新建一个文本文件,写入网站上提供的md5sum的值,空两 ...
- XMPP(一)-openfire服务端的安装和搭建
XMPP全称:可扩展通讯和表示协议 简介:可扩展通讯和表示协议 (XMPP) 可用于服务类实时通讯.表示和需求响应服务中的XML数据元流式传输.XMPP以Jabber协议为基础,而Jabber是即时通 ...
- acm入门搜索-水池数目
水池数目 时间限制:3000 ms | 内存限制:65535 KB 难度:4 描述 校园里有一些小河和一些湖泊,现在,我们把它们通一看成水池,假设有一张我们学校的某处的地图,这个地图上仅标识了此处 ...
- 在Android中使用AlarmManager
AlarmManager是Android中的一种系统级别的提醒服务,它会为我们在特定的时刻广播一个指定的Intent.而使用Intent的时候,我们还需要它执行一个动作,如startActivity, ...
- sql的简单提高效率方法
少用in操作(效率极差),尽量用表关联代替 select要指定列,不要*(*会读入所有数据,而指定列则只提取涉及的列,减少io) 尽量有where(减少读取量),where操作列尽量有索引(加快查询) ...
- 【OpenGL】理解一些基本问题
写在前面 啦啦啦,搞了很久的Unity Shaders,越学越觉得基础知识很重要.学Unity Shader的时候,总会想,shader到底是什么呢?shader的pipeline是什么呢?它们是怎么 ...
- 03 CheckBox 复选框
五 CheckBox 复选框 >概念:可以从一个集合选项中选择一个或者多个选项 >属性:checked 选择状态 >使用: > ...
- 【IOS 开发】Object - C 语法 之 流程控制
1. if 条件语句 if 表达式 : 表达式是一个 整型 或者 布尔型, 0 或者 FALSE 为 FALSE, 大于 0 为 TRUE; 代码示例 : /********************* ...
- Mybatis执行BatchExecutor(四)
BatchExecutor:顾名思义就是进行批量操作,通过批量操作来提高性能 public class BatchExecutor extends BaseExecutor { public stat ...