前言:
    2012年2月章亦春(agentzh)在Tech-Club的一次线下聚会上以《由Lua 粘合的Nginx生态环境》为主题做了演讲,分析了企业Web架构的趋势,即一个看起来完整的Web应用,往往在后台被拆分成多个Service,由多个部门分别实现,而每个部门提供給其它部门的都是http协议resful形式的接口,随后介绍了一些Nginx模块,最后讲到了将Lua嵌入到Nginx,对之所以采用Nginx+Lua来构建给出了原因。
相关链接:
http://www.tech-club.org/?p=247
http://blog.zoomquiet.org/pyblosxom/oss/openresty-intro-2012-03-06-01-13.html
http://agentzh.org/misc/slides/ngx-openresty-ecosystem/#1
正文:
     不久前,无意间看到春哥的这篇文章,也因为之前有了解过并发编程的一些概念,对Lua中的协程早有耳闻,于是花了几天时间看了Lua的语法,被这个小巧的高性能的语言所吸引,于是决定一探究竟,为方便实验,便直接下载了OpenResty,编译运行。下面与大家分享我的一些经验。
    这里以我写的开源防盗链系统(github地址https://github.com/Hevienz/nginx-lua-ds-hotlink)为例,防盗链系统的实现有两种方法,一种是检查HTTP头中的Referer字段,这种方法只能用于一般性的场合,第二种方法是为特定的IP和文件生成accesskey,然后用户通过特定的accesskey来访问特定的文件。
    首先,我们在nginx配置中配置如下,以使应用开发人员可以方便的取得accesskey。

    location = /get_key {
allow 10.0.2.2;
deny all;
content_by_lua_file lua/ds_hotlink/get_key.lua;
}

在accesskey.lua文件中调用hotlink_get_key() 函数,而此函数的实现放在init.lua之中,这样此函数在nginx启动时便被初始化,经测试,这种做法对性能的提升很明显。
在init.lua中我们实现hotlink_get_key()函数,如下:

function hotlink_get_key()
local path=ngx.var.arg_path
if not path then
ngx.exit()
end
local ip=ngx.var.arg_ip
if not ip then
ngx.exit()
end
local time=ngx.now()
local string=time..path..ip
local digest = ngx.hmac_sha1(config.secret_key, string)
ngx.say(ngx.encode_base64(time..":"..digest))
end

通过ngx.var.arg_path和ngx.var.arg_ip来分别取得url中的path和ip两个参数,然后基于时间生成散列值,附上时间信息后用base64编码后返回给客户端。
然后在需要防盗链的location下配置如下:

access_by_lua_file lua/ds_hotlink/accesskey.lua;

在accesskey.lua中依然是调用在init.lua中初始化的hotlink_accesskey_module()函数,如下:

function hotlink_accesskey_module()
local key=ngx.var.arg_key
if not key then
log{module_name="HOTLINK_ACCESSKEY_MODULE"}
ngx.exit()
end
local uri=ngx.var.request_uri
local path=nil
for i in string.gmatch(uri, "[^\\?]+") do
path=i
break
end
local user_ip=get_user_ip()
local time_digest=ngx.decode_base64(key)
if not time_digest then
log{module_name="HOTLINK_ACCESSKEY_MODULE"}
ngx.exit()
end
if not time_digest:match(":") then
log{module_name="HOTLINK_ACCESSKEY_MODULE"}
ngx.exit()
end
local tmp_dic_time_digest={}
for i in string.gmatch(time_digest,"[^\\:]+") do
table.insert(tmp_dic_time_digest,i)
end
local time=tmp_dic_time_digest[]
local digest=tmp_dic_time_digest[]
if not time or not tonumber(time) or not digest or time+config.expiration_time < ngx.now() then
log{module_name="HOTLINK_ACCESSKEY_MODULE"}
ngx.exit()
end
local string=time..path..user_ip
local real_digest = ngx.hmac_sha1(config.secret_key, string)
if digest ~=real_digest then
log{module_name="HOTLINK_ACCESSKEY_MODULE"}
ngx.exit()
end return
end

在url中取得参数key,用base64解码后得到时间和散列信息,然后用ngx.var.request_uri,用户IP和解析得到的时间来判断散列值是否相匹配,并且在其中提供诸如超时时间和日志的附属功能,相关代码比较简单,贴在这里:

local config=require("config")
fd = io.open(config.logs_pwd.."hotlink.log","ab") local function get_user_ip()
local req_headers = ngx.req.get_headers()
return (req_headers["X-Real-IP"] or req_headers["X_Forwarded_For"]) or ngx.var.remote_addr
end local function log(args)
local req_headers = ngx.req.get_headers()
local time=ngx.localtime()
local user_ip = get_user_ip()
local method=ngx.req.get_method()
local request_uri=ngx.var.request_uri
local user_agent=ngx.var.http_user_agent or "-"
local http_version=ngx.req.http_version()
local header_refer=req_headers["Referer"] or "-"
local key=ngx.var.arg_key or "-"
local line = "["..args.module_name.."] "..user_ip.." ["..time.."] \""..method.." "..request_uri.." "..http_version.."\" \""..user_agent.."\" \""..header_refer.."\" \""..key.."\"\n"
fd:write(line)
fd:flush()
end

其中的config模块如下:

module("config")

logs_pwd="/var/log/hotlink/"

----refer module----
white_domains={
"geekhub\\.cc",
} ----accesskey module----
secret_key="naudw72h2iu34298dnawi81"
expiration_time=

开发人员可以修改其中的配置,如日志路径,refer模块的域白名单,accesskey模块的secret_key和超时时间。
可能有人会问这和Web开发有什么关系,其实从这个开源软件的开发过程就可以扩展到resful形式的接口的开发。
Openresty提供了以下lib用于与上游的各种数据库进行通信:
lua-resty-memcached
lua-resty-mysql
lua-resty-redis
除此之外还有各种第三方的lib,如用于mongodb的bigplum/lua-resty-mongol等,这些lib都在其github页上提供了例子和接口文档,而将从数据库中取得的数据格式化为json格式,也是十分的方便,只需将相关的数据放到table(类似于Python中数组和字典)中,然后写下如下的代码:

local cjson = require "cjson"
ngx.say("result: ", cjson.encode(res))

对于新手来说,golgote/lua-resty-info 是一个获取OpenResty相关信息的好方法,它会提供重要的package.path和package.cpath的信息,还会列出一些变量,函数和模块的信息。这是一个demo,http://www.kembox.com/lua-resty-info.html

感谢:
     在探索OpenResty的过程中,得到了春哥以及开源社区许多朋友的帮助,才得以能够有此文章,在此表示感谢。
ruoshan https://github.com/ruoshan
wendal https://github.com/wendal
agentzh https://github.com/agentzh

由OpenResty粘合的企业Web架构的更多相关文章

  1. 《企业应用架构模式》(POEAA)读书笔记

    原文地址:<企业应用架构模式>(POEAA)读书笔记作者:邹齐龙(技术-5013 什么是架构 Rolph Johnson认为:架构是一种主观上的东西,是专家级的项目开发人员对系统设计的一些 ...

  2. Web 架构师的能力(转)

    文/刘如鸿 最近和几个朋友在谈到时下流行的Web 2.0,也提到了其中最重要的角色——架构师.多方各有争执,不外乎是因为背景和视角的缘故,包括架构一词,本身就从建筑学借鉴而来,至于架构师,则可以 简单 ...

  3. 面向服务体系架构(SOA)和数据仓库(DW)的思考基于 IBM 产品体系搭建基于 SOA 和 DW 的企业基础架构平台

    面向服务体系架构(SOA)和数据仓库(DW)的思考 基于 IBM 产品体系搭建基于 SOA 和 DW 的企业基础架构平台 当前业界对面向服务体系架构(SOA)和数据仓库(Data Warehouse, ...

  4. 撩课-Web架构师养成系列第一篇

    前言 Web架构师养成系列共15篇,每周更新一篇,主要分享.探讨目前大前端领域(前端.后端.移动端)企业中正在用的各种成熟的.新的技术.部分文章也会分析一些框架的底层实现,让我们做到知其然知其所以然. ...

  5. 撩课-Web架构师养成系列(第二篇)-async

    前言 Web架构师养成系列共15篇,每周更新一篇,主要分享.探讨目前大前端领域(前端.后端.移动端)企业中正在用的各种成熟的.新的技术.部分文章也会分析一些框架的底层实现,让我们做到知其然知其所以然. ...

  6. 高性能Web架构

    高性能Web架构 转自 架构文摘 2017-02-07 王杰  引言 最新中国互联网络信息中心(CNNIC)发布的<第38次中国互联网络发展状况统计报告>,2016年6月,我国网民规模达7 ...

  7. 分享一个大型进销存供应链项目(多层架构、分布式WCF多服务器部署、微软企业库架构)

    项目源码下载:  WWW.DI81.COM 分享一个大型进销存供应链项目(多层架构.分布式WCF多服务器部署.微软企业库架构) 这是一个比较大型的项目,准备开源了.支持N家门店同时操作.远程WCF+企 ...

  8. 从 SOA 到微服务,企业分布式应用架构在云原生时代如何重塑?

    作者 | 易立 阿里云资深技术专家 导读:从十余年前的各种分布式系统研发到现在的容器云,从支撑原有业务到孵化各个新业务,企业的发展离不开统一的.与时俱进的技术架构.本篇文章从企业分布式应用架构层面介绍 ...

  9. 从http简介到网络分层及web架构

    浏览器发起HTTP请求的典型场景 a stateless application-level request/response protocol that uses extensible semant ...

随机推荐

  1. WSDM 2014推荐系统论文

    Xiao Yu, Hao Ma, Paul Hsu, Jiawei Han On Building Entity Recommender Systems Using User Click Log an ...

  2. background-color和background-image相关细节

    1.background-color 是以border-box作为他的左上角来定位的 2.background-image 默认是以padding-box作为他的左上角来定位的 3.backgroun ...

  3. 理解Underscore中的_.bind函数

    最近一直忙于实习以及毕业设计的事情,所以上周阅读源码之后本周就一直没有进展.今天在写完开题报告之后又抽空看了一眼Underscore源码,发现上次没有看明白的一个函数忽然就豁然开朗了,于是赶紧写下了这 ...

  4. IDEA 搭建Java WEB 开发环境

    本文是一篇讲解如何在 目前比较流行的IntellJ IDEA 下搭建JavaWEB的说明文档, 如有写的不详细的地方,希望各位留下自己宝贵的意义. Tips : 遇到的问题 , 请耐心看完文章,在文章 ...

  5. 用sql语句实现年龄分段统计

    SELECT CASE WHEN (age >= 10 AND age <= 20) THEN '10-20' WHEN (age >= 21 AND age <= 30) T ...

  6. Struts2注解开发

    Hibernate和spring框架的开发前边总结了,这次看一下流行的MVC流程框架Struts2的注解开发吧.Struts2主要解决了从JSP到Action上的流程管理,如何进行Uri和action ...

  7. 【[HAOI2009]逆序对数列】

    发现自己学了几天splay已经傻了 其实还是一个比较裸的dp的,但是还是想了一小会,还sb的wa了几次 首先这道题的状态应该很好看出,我们用\(f[i][j]\)表示在前\(i\)个数中(即\(1-i ...

  8. VS2013没有安装部署,安装图解

    自vs2012后就已经没有安装向导了,VS2013安装是不带安装部署的,用 InstallShield Limited Edition for Visual Studio 解决安装部署问题 第一步:“ ...

  9. vue通过watch对input做字数限定

    <div id="app"> <input type="text" v-model="items.text" ref=&q ...

  10. ui-element消息类型 MessageBox 弹框 type类型

    MessageBox 弹框 type字段表明消息类型,可以为success,error,info和warning