电商详情页案例介绍

电商的详情页是并发量很高的服务,开发者通常采用静态化或缓存的方式减少后台服务器的压力

案例的技术点:

  1. OpenResty服务器,
  2. Lua调用Redis
  3. Lua的http模块
  4. Lua页面模板

下面先使用几个案例,介绍这些技术点

使用Lua连接Redis

OpenResty的库中自带的resty.redis可以用于连接Redis

在openresty/nginx/conf新建lua目录,新建redis_test.lua文件

-- 导入resty.redis
local redis = require "resty.redis"
-- 创建redis对象
local red = redis:new()
-- 连接redis ok返回成功信息,erro是错误信息
local ok,err = red:connect("127.0.0.1",6379)
if not ok then
        ngx.say("connect failed",err)
        return
end
-- 调用set命令
ok,err = red:set("city","wuhan")
if not ok then
        ngx.say("redis set failed",err)
        return
end
ngx.say("set city ok<br>")
-- 调用get命令
local val,err = red:get("city")
if not val then
        ngx.say("redis get failed",err)
        return
end
if val == ngx.null then
        ngx.say("city is null")
        return
end
-- 输出结果
ngx.say("city==>",val)

修改nginx.conf

server {
        listen 8080;
        location /redis_test {
           default_type text/html;
           content_by_lua_file conf/lua/redis_test.lua;
        }
}

重启nginx,访问

lua网页设置uci配置 lua获取网页_nginx

使用Lua发送HTTP请求

使用Lua发送http请求可以借助开源框架 lua-resty-http

https://github.com/ledgetech/lua-resty-http

下载文件:http_headers.lua、http.lua、http_connect.lua

保存到openresty/lualib/resty目录下

基本的http请求

创建http_test.lua

-- 创建连接对象
local httpc = require("resty.http").new()
-- 发送GET请求
local res, err = httpc:request_uri("http://192.168.101.11:8001/item?id=99", {
    method = "GET",
    headers = {
        ["Content-Type"] = "application/x-www-form-urlencoded"
    }
})
if not res then
    ngx.log(ngx.ERR, "request failed: ", err)
    return
end
-- 返回请求内容
local status = res.status
local length = res.headers["Content-Length"]
local body   = res.body
ngx.say("body:",body)

使用SpringBoot开发接口

@RestController
public class HelloController {

    @Value("${server.port}")
    private Long port;

    @RequestMapping("item")
    public String item(Long id){
        return "From: "+ port +",Get Item " + id;
    }
}

修改nginx.conf

location /http_test3 {
 	default_type text/html;
	content_by_lua_file conf/lua/http_test.lua;
 }

重启nginx,访问

lua网页设置uci配置 lua获取网页_lua_02

URL哈希实现负载均衡

下面案例通过对id参数进行哈希运算,对服务器列表实现负载均衡

local http = require("resty.http").new()  
-- 服务器列表
local hosts = {"192.168.101.11:8001","192.168.101:11:8002"}
-- 获得id参数
local item_id= ngx.var.arg_id
if not item_id then
	ngx.say("id is null")
	return
end
-- 获得哈希值
local id_hash = ngx.crc32_long(item_id)
-- 计算下标 lua从1开始
local index = (id_hash % 2) +1
-- 通过下标获得主机名,执行GET请求
local resp, err = http:request_uri("http://"..hosts[index], {  
    method = "GET",  
    path = "/item?id="..item_id,  
    headers = {  
        ["Content-Type"] = "application/x-www-form-urlencoded"  
    }  
})
if not resp then  
    ngx.say("request error :", err)  
    return  
end  
ngx.say(resp.body)  
http:close()

让后台接口在8001和8002两个端口启动,不同的id会访问不同的服务器

lua网页设置uci配置 lua获取网页_redis_03

使用Lua创建页面模板

lua-resty-template可以使用Lua创建类似JSP的模板

https://github.com/bungle/lua-resty-template

下载template和template.lua,保存到resty中

基本使用

view_template.lua

local template = require "resty.template"
-- 方法1 使用new方法进行页面渲染,message是自定义数据
local view = template.new "view.html"
view.message = "Hello, World!"
view:render()
-- 方法2 使用render实现页面渲染
template.render("view.html", { message = "Hello, World!" })

nginx/html/view.html

<!DOCTYPE html>
<html>
<body>
  <h1>{{message}}</h1>
</body>
</html>

nginx.conf

location /view_template {
     default_type text/html;
     content_by_lua_file conf/lua/view_template.lua;
     root html;
     index view.html;
}

访问效果

lua网页设置uci配置 lua获取网页_nginx_04

Lua+Redis+OpenResty实现电商详情页

实现思路

lua网页设置uci配置 lua获取网页_redis_05

course.lua

-- 获得路径参数id
local id = ngx.var.id
-- 连接redis
local redis = require "resty.redis"
local red = redis:new()
local ok,err = red:connect("127.0.0.1",6379)
if not ok then
        ngx.say("connect failed",err)
        return
end
-- 查询该id的课程
local val,err = red:get("course"..id)
if not val then
        ngx.say("redis get failed",err)
        return
end
if val == ngx.null then
		-- 缓存为空,查询后台接口
		local httpc = require("resty.http").new()
		local res, err = httpc:request_uri("http://192.168.101.18:8002/course/"..id, {
			method = "GET",
			headers = {
				["Content-Type"] = "application/x-www-form-urlencoded"
			}
		})
		if not res then
			ngx.log(ngx.ERR, "request failed: ", err)
			return
		end
		val = res.body
		if val == ngx.null then
			ngx.say("course not found ",id)
			return
		end
		-- 保存到redis
		red:set("course"..id,val)
end
-- 实现页面渲染
local template = require "resty.template"
template.caching(false)
local context = {
	course = val
}
template.render("course.html", context)

nginx.conf

location ~*/course/([0-9]+)$ {
    default_type text/html;
    root html;
    set $id $1;  #获得uri最后的数字保存到id变量中,lua中通过ngx.var.id获得
    index course.html;
    content_by_lua_file conf/lua/course.lua;
}

course.html\css\js 保存到nginx/html目录中

页面使用了Vue.js,其中Vue的{{ }}符号和Lua模板冲突,所以需要使用{-raw-}括起来,Lua不进行处理

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>课程页面</title>
    <link rel="stylesheet" type="text/css" href="/css/course.css">
</head>
<body>
<div id="course">
    <div style="background: #eee;">
        <div class="nav-wrap">
            <p class="nav-p-pc" style="margin-top:-25px;text-align:left;">
                <a href="/">课程列表</a>
                <span class="sharp-content">></span>
                <span class="nav-sec">{-raw-}{{course.courseName}}{-raw-}</span>
            </p>
        </div>
        <!-- 课程详情 -->
        ...
        {-raw-}{{course.price}}{-raw-}
        ...
    </div>
</div>
</body>
<script src="/js/vue.js"></script>
<script>
    var vue = new Vue({
        el: "#course",
        data: {
            course:{*course*} //以非转义方式绑定lua模板中的course对象
        },
        created() {
            console.log(this.course);
        }
    });
</script>
</html>

后台查询接口

@RestController
public class CourseController {

    @Autowired
    private CourseService courseService;

    @GetMapping("course/{courseid}")
    public Course getCourseById(@PathVariable("courseid")Integer courseid) {
        Course course = courseService.getCourseById(courseid);
        return course;
    }
}

访问效果

lua网页设置uci配置 lua获取网页_电商系统_06