mochiweb运行总体流程
自定义模块start/1函数调用mochiweb_http:start([{name, ?MODULE}, {loop, ?LOOP},{port,Port])启动整个项目
1 启动mochiweb_socket_server进程,并将该进程转化为系统进程,作为各子进程的监控进程
2 创建进程池,挂载多个accept进程,并将各进程pid存入连接池(accept_pool),通过记录#mochiweb_socket_server{}维护
3 挂载的accept进程等待用户连接,若存在用户连接,则立即向mochiweb_socket_server进程发送accepted消息,并建立连接,然后以mochiweb_http:loop/3为入口接收http请求并调用自定义模块处理请求响应用户
4 mochiweb_socket_server进程接收到accepted消息,立即调整#mochiweb_socket_server{}记录信息,将其中active_sockets+1,并将其进程pid从acceptor_pool中移除,最后在创建一个新的acceptor进程,维持当前挂载的acceptor进程数稳定
5 Socket连接断开,若断开异常则向监控进程mochiweb_socket_server发送异常信息,监控进程首先查看该进程pid是否存在acceptor_pool中,若存在则编写错误日志,否则直接调用mochiweb_socket_server:recycle_accceptor/2更新#mochiweb_socket_server{}记录信息,若正常断开,则监控进程接收到{'EXIT',Pid,normal}消息,则直接调用mochiweb_socket_server:recycle_acceptor/2
Http请求处理
1 Http消息头信息处理,循环调用mochiweb_http:header/6处理函数,提取头信息形成一个元组列表[{HeaderName1,HeaderValue1},{...},...]
2 调用mochiweb_request模块生成一个参数化模块mochiweb_request实例,其中包含套接字,请求方法(GET,POST等),Http版本等,这里用Req表示实例,Req={mochiweb_request,[Socket,Opts,Method,RawPath,Version,Headers]}
3 通过mochiweb_request:call_boy/2函数调用用户自定义模块(?MODULE:loop(Req))对Http请求进行相应处理并响应浏览器
4 查看Http请求情况,执行Socket连接关闭或Req对象清理,保持连接继续执行自定义模块信息处理(保持连接情况:Http请求处理未完成,存在Keep-alive或chunk类型的Http请求)
Http消息响应
单个消息使用Request对象实例(Req)响应
1 直接调用Req:respond({Code,ResponseHeaders,Body})给浏览器发送Response,这里传入的元组参数中,Code表示Http状态码,ResponseHeader是响应消息头列表,列表元素是二元二组Key-Value对,Key和Value都是字符串([{"Content - Type","text/plain"}]),Body表示需要发送给浏览器的Response
2 若需要返回静态文件(xxx.html),则通过调用Req:serve_file(Path,DocRoot)直接将文件发送给浏览器,其中DocRoot表示Web根目录,Path表示相对路径,两者结合可直接定位需返回的静态文件
3 若请求Url不存在可直接调用Req:not_found(),返回浏览器“Not found.”,接收到无法理解或者不支持的的Http请求,则可以直接调用Req:respond({501,[],[]})
连续多个消息使用Response响应
Req:respond会返回一个mochiweb_response参数化实例对象(Response),Response中包含Req实例对象,响应状态码,响应消息头等信息([Request,Code,Headers]),Response实例对象包含一个send函数,用于间接调用Req:send函数响应浏览器,这里感觉是否多此一举,其实Response设置send函数是为了方便发送HTTP 1.1中的chunked数据,完成第一次响应后,后继的chunk数据即可通过最初返回的Response对象调用write_chunk()继续发送,write_chunk判定请求消息头中的HTTP 版本后,调用Response:send,分别以不同的格式发送响应
实例修改
1 定位mochiweb_example_web:loop/2函数,在其case分支中添加“welcome.html”和“timer”,并编写相应处理
2 在注释“%%Internal API”下添加timer/1函数,代码可以查看截图
3 在项目根目录/priv/www/中自定义一个welcome.html文件
修改完成后,在项目根目录下打开shell窗口,运行make命令重新编译整个项目,编译成功后,执行sh start-dev.sh,运行成功后打开浏览器,可尝试输入网址:
localhost:8080
localhost:8080/hello_world
localhost:8080/welcome.html
localhost:8080/timer
附加:亦可自定义模块,并定义loop函数,直接调用mochiweb_socket_server启动进程,针对外界连接自定义处理