1. 程式人生 > >openresty 前端開發進階一之http後端

openresty 前端開發進階一之http後端

做前端開發,大多數情況下,都需要跟後端打交道,而最常見的方式則是通過http請求,進行通訊。

在openresty中,通過http跟後端整合通訊的方式又很多種,各有各的好處,可以根據情況交叉使用

1、直接proxy

這種方式最簡單,也是我們最熟悉的,直接配置一個反向代理,跟nginx的用法一致

比如我們有一個後端服務,提供使用者相關介面,是java寫的,埠8080,為了簡單起見,我直接在openresty裡面配置一個server,模擬java端,通過一個簡單的案例的來說明情況

nginx.conf


worker_processes  1;

error_log logs/error.log;

events
{ worker_connections 1024; } http { lua_package_path "/Users/john/opensource/openresty-web-dev/demo7/lua/?.lua;/usr/local/openresty/lualib/?.lua"; server { listen 80; server_name localhost; lua_code_cache off; location / { root html; index index.html; } location
~ ^/user { proxy_pass http://127.0.0.1:8080; } } # 這個只是模擬後端 server { listen 8080; server_name localhost; lua_code_cache off; location ~ /user/(.+) { default_type text/html; content_by_lua_file lua/$1.lua; } } }

上面配置了兩個location,將所有以/user開頭的請求都轉到後端的8080伺服器,其他的則是靜態頁面,直接從html目錄讀取,然後返回,從這裡開始就是前端開發了

為了簡單起見,假設後端提供了一個登陸介面,我們這裡直接用lua來實現一下就好了,檢查使用者名稱跟密碼是admin,就返回成功,否則返回失敗

lua/login.lua

local req = require "req"
local cjson = require "cjson"

local args = req.getArgs()

local username = args['username']
local password = args['password']

local res = {}

if username == "admin" and password == "admin" then
    res['ret'] = true
    res['token'] = ngx.md5('admin/' .. tostring(ngx.time()))
else
    res['ret'] = false
end

ngx.say(cjson.encode(res))

index.html

<html>
<head>
    <meta charset="UTF-8">
    <title>Login Page</title>
</head>
<body>
    UserName: <input type="text" id="username" value="admin">
    Password: <input type="password" id="password" value="admin">
    <a href="javascript:void(0)" onclick="login()">Login</a>
    <script src="//cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
    <script>
        function login() {
            var username = $('#username').val();
            var password = $('#password').val();
            $.post('/user/login', {username: username, password: password}, function(res){
                console.log(res)
                var msg = res.ret ? "登入成功" : "登入失敗"
                alert(msg)
            }, 'json')
        }
    </script>
</body>
</html>

2、使用ngx.location.captrue

這個方法主要用於傳送內部請求,即請求當前server內的其他location,預設會將當前請求的引數帶過去,也可以手動指定引數,GET引數通過args傳遞,post引數通過body傳遞

如:

local req = require “req”
local args = req.getArgs()

GET 呼叫

local res = ngx.location.capture(‘/user/login’, {
method = ngx.HTTP_GET,
args = args,
});

POST 呼叫

local res = ngx.location.capture(‘/user/login’, {
method = ngx.HTTP_POST,
body = ngx.encode_args(args),
});

現在我們自己寫一個lua來呼叫後臺介面實現登陸,然後對請求做一點處理,實現一些額外的邏輯,比如在原來的引數上面加上一個from欄位

lua/local-login.lua

local req = require "req"
local cjson = require "cjson"

local args = req.getArgs()

-- GET
local res = ngx.location.capture('/user/login', {method = ngx.HTTP_GET, args = args})
-- POST
-- local res = ngx.location.capture('/user/login', {method = ngx.HTTP_POST, body = ngx.encode_args(args)})

-- print(res.status) -- 狀態碼

if res.status == 200 then
    local ret = cjson.decode(res.body)
    ret['from'] = 'local'
    ngx.say(cjson.encode(ret))
else
    print(res.body)
    ngx.say('{"ret": false, "from": "local"}')
end

index.html 也需要改一下,多加一個按鈕,呼叫本地登陸介面

<html>
<head>
    <meta charset="UTF-8">
    <title>Login Page</title>
</head>
<body>
    UserName: <input type="text" id="username" value="admin">
    Password: <input type="password" id="password" value="admin">
    <a href="javascript:void(0)" onclick="login()">Login</a>
    <a href="javascript:void(0)" onclick="local_login()">Local Login</a>
    <script src="//cdn.bootcss.com/jquery/2.2.4/jquery.min.js"></script>
    <script>
        function login() {
            var username = $('#username').val();
            var password = $('#password').val();
            $.post('/user/login', {username: username, password: password}, function(res){
                console.log(res)
                var msg = res.ret ? "登入成功" : "登入失敗"
                alert(msg)
            }, 'json')
        }

        function local_login() {
            var username = $('#username').val();
            var password = $('#password').val();
            $.post('/lua/local-login', {username: username, password: password}, function(res){
                console.log(res)
                var msg = res.ret ? "本地登入成功" : "本地登入失敗"
                alert(msg)
            }, 'json')
        }

    </script>
</body>
</html>

這種方式跟上面那種不同的地方是呼叫的時候,不會帶上本地請求的請求頭、cookie、以及請求引數,不過這也使得請求更純粹,不會帶上那些沒必要的東西,減少資料傳輸

最後local-login.lua 變成如下

local req = require "req"
local cjson = require "cjson"
local http = require "resty.http"

local args = req.getArgs()

-- GET
-- local res = ngx.location.capture('/user/login', {method = ngx.HTTP_GET, args = args})

-- POST
-- local res = ngx.location.capture('/user/login', {method = ngx.HTTP_POST, body = ngx.encode_args(args)})

-- http
local httpc = http.new()
local res = httpc:request_uri("http://127.0.0.1:8080/user/login", {
    method = "POST",
    body = ngx.encode_args(args),
    headers = {
        ["Accept"] = "application/json",
        ["Accept-Encoding"] = "utf-8",
        ["Cookie"] = ngx.req.get_headers()['Cookie'],
        ["Content-Type"] = "application/x-www-form-urlencoded",
    }
})
httpc:set_keepalive(60)

print(res.status) -- 狀態碼

if res.status == 200 then
    local ret = cjson.decode(res.body)
    ret['from'] = 'local'
    ngx.say(cjson.encode(ret))
else
    print(res.body)
    ngx.say('{"ret": false, "from": "local"}')
end

到此,基本上已經能通過openresty,做一些前後端的互動了,下次介紹怎麼使用openresty模板渲染,以及搭配react開發前端。

示例程式碼 參見demo7部分