前言:
    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. January 18 2017 Week 3 Wednesday

    True liberty is to have power over oneself in all things. 真正的自由是在所有的事情上都能控制住自己. Liberty isn't meanin ...

  2. 理解Underscore中的restArgs函数

    虽然Underscore并没有在API手册中提及到restArgs函数,我们仍然可以通过_.restArgs接口使用restArgs函数.如果不去阅读源码,我们很难发现Underscore中还有这样的 ...

  3. Ubuntu16.04死机解决方案

    内核下载地址:http://kernel.ubuntu.com/~kernel-ppa/mainline/ Ubuntu 16.04 LTS,电源设置里面的休眠/挂起/睡眠功能会使电脑会进入死机状态, ...

  4. Mycat数据库中间件对Mysql读写分离和分库分表配置

    Mycat是一个开源的分布式数据库系统,不同于oracle和mysql,Mycat并没有存储引擎,但是Mycat实现了mysql协议,前段用户可以把它当做一个Proxy.其核心功能是分表分库,即将一个 ...

  5. PHP中的 array_filter 函数

    <?php function test_odd($var) { return($var & 1); } $a1=array("a","b",2,3 ...

  6. 虚拟机Centos安装docker小记

    本书记录是参考 <Spring Cloud 与 Docker 微服务架构实战(第二版)>这本书实现的. 记录简单几个命令,安装顺序如下: 1. 安装docker所需的包 sudo yum ...

  7. 隐藏C#的TabControl控件的选项卡TabPage

    在使用TabControl控件时,希望隐藏其中某个选项卡(即TabPage).TabPage类明明提供了一个Hide方法,用在代码中却没有任何效果,甚是奇怪.无奈之余,只好考虑另辟途径.方法一:设置该 ...

  8. 用python实现ping

    #!/usr/bin/env python #coding=utf-8 import os import argparse import socket import struct import sel ...

  9. java使用Redis(六个类型)

    下载插件:https://mvnrepository.com/artifact/redis.clients/jedis/3.0.0 maven项目依赖: <dependency> < ...

  10. 一个有意思的CSS样式库--BUTTONS

    我最近发现了一个有意思的CSS样式库,和Bootstrap相似,但是它是专门的一个高度可定制的,免费的并且开源的按钮CSS样式库,这里附上它的网址:http://www.bootcss.com/p/b ...