`
dxm1986
  • 浏览: 434269 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Mochiweb的设计分析

阅读更多

 

Mochiweb的设计分析

March 15th, 2009 :: refactor

转自:http://erlang-china.org/misc/mochiweb-inside.html

Web服务器的基本工作大致分3步: 

  1. 接收HTTP请求; 
  2. 处理HTTP请求,生成响应内容;
  3. 发送响应

一、处理请求和发送响应 

模块mochiweb_request可说是Mochiweb处理HTTP请求的核心部分,它总共负责了第2步和第3步工作。因此参数化模块mochiweb_request的实例不像它的模块名那样单纯:它还负责将请求的响应(通过Socket连接,调用gen_tcp:send)发还(response)给浏览器。这个模块是一个参数化模块。这意味着它具有基于对象(Object-based)的特点,它的每个实例化对象代表一个用户请求,用户可以像OO那样操作HTTP请求:获取请求信息,生成响应内容等。 

对静态内容(如html文件,静态图片)来说,无非是读取文件系统中静态文件的内容作为响应消息体(Body)发送给客户端浏览器。 

对动态内容来说,生成响应内容的业务逻辑是用户通过编程实现的:解析请求(包括URL路径和HTTP请求头),然后生成相应的响应内容。用户编写业务逻辑处理函数,然后将函数插入到mochiweb中。此函数带有一参数,该参数是参数化模块mochiweb_request的实例(假设为Req),在这个定制函数中可以通过这个Req实例对象获取浏览器请求的所有信息(包括URL路径和HTTP请求头),处理后的响应数据也通过Req实例提供的函数发还给浏览器,有好几种方式: 

  1. 通过Req实例对象直接发还给浏览器

     

      a) 通过这个Req实例对象的response/1函数直接发还给浏览器:
      Req:response({Code, ResponseHeaders, Body})
      这个函数接收一个tuple参数,参数的第一个元素是HTTP状态码(比如200),第二个元素是响应消息头列表(一个二元tuple,key和value都是字符串,如{“Content-Type”, “image/jpeg”}),第三个元素即为HTTP响应内容;如果是动态内容,采用response函数直接发还响应数据还是比较方便的。

      b) 如果是静态文件,通过Req的serve_file(…)函数可以直接将文件发还给浏览器,告诉此函数文件的Web根目录(doc_root)和相对路径就可以将指定的静态文件发给浏览器了。doc_root目录一般在配置文件中设置,这个目录下的所有文件都可以通过HTTP访问。

      c) 一些常见的例行响应:
      不存在的URL请求返回404错误,可以直接调用Req:not_found() 若一切正常,调用Req:ok({…, Body})直接返回状态码为200的HTTP响应
      b,c两种情况的内部其实还是调用的Req:response()

  2. 通过Response模块对象将响应发还给浏览器

     

      Req:response函数会返回一个mochiweb_response参数化模块实例对象(假设为Response),Response实例对象包含有对应的Req实例对象。通过Response对象可以得到响应的相关信息(如响应状态码,响应消息头,对应的Req对象),它还有一个send函数可以将响应数据发还给浏览器(它的实现其实还是调用Req对象的send函数进行的)。Response之所以还要有send函数是为了发送chunked数据(HTTP 1.1)的方便,在第一次响应完成后,后继的chunk数据就可以通过最初返回的Response对象继续进行发送了,为此Response有个函数write_chunk()专门干这事,write_chunk检查了请求消息头中的HTTP 版本消息后就调用Response:send。

      因此,响应内容最终都是由参数化模块mochiweb_request的response/1函数发送的。而这个response(…)函数内部最后调用了Req:send(Data)函数将响应通过socket连接(调用gen_tcp:send)返还给浏览器,这一发送过程又分成两个阶段:响应消息头(Headers)的发送和消息体(Body)的发送,这两步都是通过Req:send完成的。

小结:对于程序员来说,他编写的服务器端处理HTTP请求的函数必须带有一个参数,这个参数代表了mochiweb_request参数化模块的一个实例对象。通过这个实例程序员可以得到HTTP请求的所有信息(包括路径、请求参数以及HTTP请求消息头),然后生成响应,他还可以通过该mochiweb_request实例对象将响应数据发还给浏览器。 

  • 如果响应的是静态文件,可以通过Request:server_file()函数发送响应;
  • 如果响应是动态生成的内容,通过Request:response()函数发送响应数据(文本数据和二进制数据都可以);
  • 如果是chunk响应,第一次调用Request:response()函数发送数据后,该函数会返回一个Response实例对象(参数化模块mochiweb_response的一个实例),以后的响应数据可以通过这个Response实例对象(调用Response:write_chunk(Data))发送后续的响应数据。

二、Web服务器的业务处理逻辑如何嵌入到Mochiweb 

业务处理逻辑被程序员编写成一个函数(函数式编程中函数也是一种数据,以下称为HttpLoop),处理函数HttpLoop是作为mochiweb启动时的参数之一进入Mochiweb,Mochiweb是这样启动的: 

mochiweb_http:start([{loopHttpLoop},...])  

Request实例对象最终要调用gen_tcp:send(Socket,…)将响应数据由socket连接发给浏览器,因此,Request实例对象应该持有HTTP请求的socket连接。这个目标是这样实现的: 
在启动过程中,mochiweb_http又对用户的HttpLoop函数进行了重新包装 

Loop = fun (Socket) ->
    
mochiweb_http:loop(SocketHttpLoop)
end,

每个浏览器连接请求对应着一个Socket连接,新的Loop函数以此Socket作为参数,然后通过mochiweb_http:loop函数对Socket连接和用户自定义的HttpLoop函数进行了处理,简单的说,这个函数做了如下工作: 

  1. 将Socket连接设置成能处理HTTP数据包 (inet:setopts(Socket, [{packet, http}]));
  2. 准备接收socket连接传来的数据(gen_tcp:recv(Socket,…));

当收到数据时:

  1. 将HTTP消息头数据提出(成为{HeaderName, HeaderValue}的tuple列表)
  2. 生成一个参数化模块mochiweb_request的实例对象,并将Socket连接、HTTP请求信息(路径、请求方法、HTTP版本)以及请求消息头列表包装到此实例对象中,
  3. 然后调用用户的HttpLoop对请求进行处理和响应(如前所述,处理得到的响应数据也在用户编写的HttpLoop函数中被发送给浏览器)
  4. 最后根据HTTP请求信息决定是简单的关闭Socket连接,还是清理一下Req对象并保持连接(例如对keep-alive,chunk等类型的HTTP请求,以及还没完成数据传送的HTTP请求),以便继续让HttpLoop函数进行处理,

这都是在headers函数中进行的,还是看mochiweb_http模块的代码: 

  1. headers(SocketRequestHeadersHttpLoopHeaderCount) -> 
  2.     case gen_tcp:recv(Socket0, ?IDLE_TIMEOUT) of 
  3.         {okhttp_eoh} -> 
  4.             inet:setopts(Socket[{packetraw}])
  5.             % 将Socket连接、HTTP请求信息(路径、请求方法、HTTP版本)以及请求消息头列表打包成参数化模块(mochiweb_request)的实例对象 
  6.             Req = mochiweb:new_request({SocketRequest
  7.                                         lists:reverse(Headers)}),   
  8.             HttpLoop(Req)% 让用户编写的函数处理HTTP请求 
  9.            case Req:should_close() of 
  10.                 true ->  
  11.                     gen_tcp:close(Socket)
  12.                     exit(normal)
  13.                 false ->  
  14.                     Req:cleanup()
  15.                     mochiweb_http:loop(SocketHttpLoop) 
  16.             end
  17.         {ok, {http_header_Name_Value}} -> 
  18.             headers(SocketRequest[{margin-
    分享到:
    评论

相关推荐

    mochiweb实例

    这个实例将帮助我们理解Mochiweb是如何工作的,并如何使用它来构建一个简单的Web服务器。Erlang是一种并发性极强、容错性高的语言,特别适合构建分布式系统,而Mochiweb则是Erlang生态系统中的一个重要组件。 首先...

    erlang mochiweb-test demo

    这个 "erlang mochiweb-test demo" 压缩包很可能是为了展示如何使用 Mochiweb 在 Erlang 中构建一个简单的 Web 应用程序或测试环境。 Mochiweb 的核心组件包括以下几个部分: 1. **HTTP 服务器**:Mochiweb 提供了...

    基于mochiweb的聊天室

    通过学习和分析这个项目,开发者可以深入理解Erlang的并发模型、Mochiweb的工作原理,以及如何利用它们构建高效、可靠的Web服务。同时,这也为扩展到更复杂的实时应用,如协作工具、游戏服务器等,提供了基础。

    mochiweb:MochiWeb 是一个用于构建轻量级 HTTP 服务器的 Erlang 库

    MochiWeb 的最新版本可在MochiWeb 的邮件列表位于 设置 MochiWeb 环境需要 Erlang OTP,可在使用项目创建一个新的 mochiweb:make app PROJECT=project_name 要使用特定目录中的项目创建新的 mochiweb: make app ...

    mochiweb:Mochi Media出色的HTTP库的一个分支-可以在https上找到其规范源

    MochiWeb的邮件列表位于 R12B兼容性:MochiWeb的母版已通过R14A及更高版本进行了测试。 与R12B兼容的分支在单独维护。为方便起见,该存储库的R12B分支有时会在官方存储库中进行镜像。 要使用项目创建新的mochiweb,...

    erlang web frame

    - **轻量级**:Mochiweb和Cowboy都设计为轻量级,启动快速,资源占用少,适合部署在资源有限的环境中。 总的来说,Erlang Web框架如Mochiweb和Cowboy,为开发者提供了一种高效且可靠的构建Web服务的方式,尤其适用...

    张琨:教育社交平台的web架构分享

    NoticeSystem则利用了mochiweb的高效通信特性,采用了Erlang编程语言。MQserver使用了RabbitMQ作为基础的异步消息队列服务,而FileStoreServer结合了Varnish和MongoDB来实现静态资源的存储。 具体服务与应用的设计...

    erlang-rpssl-comet:使用Mochiweb和Comet技术的Erlang网页游戏-Rock-Paper-Scissors-Spock-Lizard

    RPSSL彗星 RPSSL-Rock-Paper-Scissors-Spock-Lizard是一款简单但着名的2人游戏。 通常,它是第一人称自己玩的,但这是网络版本。 ... ... 因为它使用的资源很少,所以我们可以使其永远处于阻塞状态,并保持连接处于打开...

    erlang实战IP查询服务

    通过以上分析,我们可以看到该项目不仅是一次实际操作的体验,也是对Erlang语言特性及其在Web开发领域应用的一次深入探索。对于有兴趣学习Erlang或者希望深入了解其在网络编程中的应用的开发者来说,这是一个非常有...

    Erlang高级应用和原理

    在国外,Erlang被广泛应用于Ejabberd即时通讯服务器、RabbitMQ消息队列、CouchDB文档数据库、Mochiweb轻量级Web服务器以及Disco分布式计算框架。 Erlang与传统的操作系统如Unix相比,具有独特的设计哲学。在Unix中...

    SNS社区网站WEB即时通信技术解决方案

    - WebIM服务器使用Erlang的“mochiweb”实现,可以支持大量的并发长连接,从而确保系统的高可用性和扩展性。 - **消息接口设计**: - AJAX POST消息:用户通过POST方式向SNS主服务器发送消息。 - 主服务器处理并...

    CloudFoundry - The building of the Open PaaS Presentation

    2. **多框架兼容**:支持各种框架,例如Spring、Grails、Express、Rails、Lift、MochiWeb等。 3. **多服务集成**:能够与多种数据服务和其他服务集成,如MySQL、PostgreSQL、MongoDB、Redis、RabbitMQ等。 4. **多云...

    Webmachine.zip

    Webmachine 是一个应用层,为 mochiweb 提供 HTTP 语义的特性,定义一个简单而清晰的连接应用的方式。 标签:Webmachine Web框架

    simple_bridge:一个简单,标准化的Erlang HTTP服务器接口库

    它目前支持Cowboy,Inet,Mochiweb,Webmachine和Yaws。 SimpleBridge用作两个最受欢迎的Erlang Web框架到Web服务器的桥梁: 和 从某种意义上讲,它类似于 ,除了具有一些关键的改进/不同之处: 轻松扩展-需要...

    web1

    【标题】:深入理解Erlang在Web开发中的应用...通过以上分析,我们可以看到,"web1"项目利用Erlang的强大功能,构建了一个高效、可靠的Web服务。对于想要深入理解和应用Erlang的开发者来说,这是一个值得研究的实例。

    awesome-erlang:精湛的Erlang框架,库和软件的精选列表

    专为高质量和工业用例而设计。 -Tsung是适用于各种协议(包括HTTP,XMPP,LDAP等)的高性能基准框架。 -Lisp风味Erlang(LFE) -Erlang Web MVC,现在具有Comet功能 -MochiWeb是用于构建轻量级HTTP服务器的Erlang库...

    erlang websocket

    2. **Erlang实现Websocket**:在Erlang中,可以使用如`cowboy`或`mochiweb`这样的Web框架来处理Websocket连接。它们提供了方便的中间件,使得在Erlang进程中直接处理Websocket连接成为可能。例如,`cowboy`中的`...

    Good for restful API

    该框架基于Mochiweb(一款用Erlang编写的Web服务器)构建,旨在帮助开发者轻松构建遵循HTTP语义的服务,同时避免了在业务逻辑中直接处理HTTP相关的复杂性。 ##### 原则 - **默认行为**:Webmachine实现了一些默认...

    Erlang的高级特性和应用

    - Profile:性能分析工具 - 工具集:提供各种开发辅助工具 **Erlang 的高性能和高可靠性** Erlang 以其简洁的代码实现高并发,如单个CPU可以处理16000个并发请求,优于某些顶级的Web服务器。其代码覆盖率工具cover...

Global site tag (gtag.js) - Google Analytics