萬盛學電腦網

 萬盛學電腦網 >> 網絡編程 >> 編程語言綜合 >> Lua和Nginx結合使用的超級指南

Lua和Nginx結合使用的超級指南

   這篇文章主要介紹了Lua和Nginx結合使用的指南,從數據轉換到API等各個方面均有涉及,超推薦!需要的朋友可以參考下

  Nginx作為API代理

  有很多原因說明你為什使用nginx作為API代理。首先因為他是開源的;其次,Nginx有大量的安裝基礎,他背後有一個強大的社區支持,在性能方面也表現的非常出色。對於我們來說,這是顯而易見的,如果開源軟件有相同的解決方案我們為啥還要用那些私有的軟件。

  另外一個極大的優勢就是nginx對lua的支持,nginx+lua是一個非常好的組合,它允許使用一個高性能的腳本語言擴展nginx。nginx有很多方法是自帶的,但是使用lua沒有限制的。

  原理很簡單。有沒有這樣的情況你更喜歡使用基於nginx的API代理而不是它自帶的方法呢?呵呵,你可以非常簡單的添加。

  擴展目標: Sentiment API (可以是任何API)

  為了展示nginx和lua的強大之處,我們將使用一個簡單的REST API調用Sentiment,不使用任何一行API源碼(可以直接使用github上的)。

  Sentiment API 是一個非常基礎的API,它返回一個有情感價值分析的單詞或者句子。比如,下面的請求(你可以自己試試)

   代碼如下:

  curl http://api-sentiment.3scale.net/v1/word/fantastic.json

  上面的請求將返回包含fantastic情感分析單詞的json串。

   代碼如下:

  {"sentiment":4,"word":"fantastic"}

  我們有了擴展對象,接下來繼續吧…

  分析部分: 擴展Sentiment API

  有很多方式你可以擴展Sentiment API(或者你自己的API)。為了符合這篇文章的主題,我們限定了三種場景來展示nginx+lua的強大之處和可擴展性。

  1) 想做數據轉換?

  想把輸出數據從json轉換為xml格式?或者更好一些,把xml轉換為json。

  2) 想更換你的API方法的簽名?

  你想把漂亮的 REST形式的url path/v1/word/WORD.json替換為貌似更加 “漂亮的” 簽名方式 parameters/sentiment?action=word&word=WORD&version=v1.

  我們不能容忍變成那樣的路徑方式:-)這應該是個反面例子,自從Sentiment API改為RESTful方式,這個例子應該反過來了。

  3) 想創建一個新的API方法?

  沒問題,你可以自己創建個新的API方法得到你想要的,或者有可能,你可以不接觸任何API源碼來擴展你的API方法。

  我們將展示下創建一個Sentiment API的新方法:用來查找在一個句子中最有情感分析價值的單詞。這個方法在Sentiment API沒有提供,但是我們可以通過nginx和lua創建它。

  這個案例無論對於用戶還是對於API開發者多有很大的潛能。基本上可以允許你自己在不修改源碼的基礎上定制API,或者,這還有酷斃了的一部分,允許你定制你不能控制的API。想在包含一系列方法的Twitter API上創建自己的方法?當然可以,結果可能是你的應用程序代碼更簡潔了。

  這只是使用nginx+lua擴展的三個簡單例子。還有一些其他例子我們只是為了突出使用nginx+lua擴展你的API有多麼簡單和強大。

  讓我們開始做點實際的東西吧…

  使用lua擴展nginx

  我們假設你應經對nginx基礎概念有了了解(servers, locations, 等…)

  擴展nginx我們必須先提供lua的支持,它不是ngnix的一部分。我們無需擔心因為已經有很多組件編譯進了lua,像:

  openresty (在3scale)

  tengine

  如果你堅持自己安裝 :-) 你可以自己安裝下面的組件:

  Lua nginx module

  HttpProxy module

  事實上,如果你不想用lua而是更喜歡perl,查看下這個頁面look at the CPAN page,這裡提供了全部文檔。

  基礎部分

  整個處理過程是代理請求到真實的API,主要通過下面過程:1)捕獲請求傳遞給API 2)響應請求,接著 3)處理響應。

  下面展示了nginx配置文件中的相關配置:

  代碼如下:

  upstream backend {

  # service name: API ;

  server api-sentiment.3scale.net:80 max_fails=5 fail_timeout=30;

  }

  server {

  listen 8181;

  location ~ /v1/word/(.*).json$ {

  proxy_pass http://backend/v1/word/$1.json ;

  }

  }

  這裡我們只配置了一個路由地址:/v1/word/your-word-goes-here.json。這個路由在Sentiment API上返回一個結果. Nginx 只是負責做一個簡單的傳遞。

  你可以啟動你的nginx (監聽本地端口 8181) ,用下面的方式發送一個請求

   代碼如下:

  curl http://localhost:8181/v1/word/fantastic.json

  它將返回一個同樣的json

   代碼如下:

  {"sentiment":4,"word":"fantastic"}

  我們只是給真實的Sentiment API做了個中轉。讓我們帶著興趣繼續吧…

  1) 數據轉換

  JSON 到 XML

  在nginx配置文件添加新的路由,如下:

   代碼如下:

  upstream backend {

  # service name: API ;

  server api-sentiment.3scale.net:80 max_fails=5 fail_timeout=30;

  }

  server {

  listen 8181;

  location ~ /v1/word/(.*).json$ {

  proxy_pass http://backend/v1/word/$1.json ;

  }

  location ~ /v1/word/(.*).xml$ {

  content_by_lua_file /PATH_TO/json_to_xml.lua;

  }

  }

  我們僅添加了一個新路由:/v1/word/your-word-goes-here.xml。這個路由將把 Sentiment API輸出的json轉換為xml格式。我們沒有做一個傳遞,而是通過調用一個lua文件實現邏輯的(不要擔心,很簡單)。

  現在你可以做下面的工作了,

  curl http://localhost:8181/v1/word/fantastic.xml

  你將獲取到下面信息:

  代碼如下:

  

  

  4

  fantastic

  

  這裡發生了什麼?好吧,我們基本上把Sentiment API輸出的json數據轉換成了xml格式!

  lua的魔法

  轉化json為xml需要一系列的lua libs:

  cjson :通過luarocks安裝或者在項目主頁上下載手動安裝。

  luaXml : 我們將使用一個補丁版本來使他在nginx下工作,你可以在這裡下載補丁版本here

  如果你在安裝luaxml時遇到問題,那麼可以直接安裝luarocks作為替代方案,把luaxml文件放到openresty裡面的lua lib目錄下,查找lua libs默認目錄就是openresty。

  當我們訪問xml路由時,nginx將調用lua文件

   代碼如下:

  local xml = require("LuaXml")

  require("os")

  local cjson = require "cjson"

  local path = ngx.var.request:split(" ")[2]

  local m = ngx.re.match(path,[=[/([^/]+).(json|xml)$]=]) -- match last word

  local res = ngx.location.capture("/v1/word/".. m[1] .. ".json" )

  local value=cjson.new().decode(res.body)

  local response = xml.new("response")

  response.word= xml.new("word")

  response.sentiment = xml.new("sentiment")

  response.timestamp = xml.new("timestamp")

  table.insert(response.word, value.word)

  table.insert(response.sentiment, value.sentiment)

  table.insert(response.timestamp, os.date())

  ngx.say('', xml.str(response,0))

  這個lua文件做了一個本地json請求,使用下面的配置

   代碼如下:

  local res = ngx.location.capture("/v1/word/".. m[1] .. ".json" )

  它直接請求的真實的Sentiment API,一旦你有了json對象,我們就可以按照規則轉化為xml格式,從

  復制代碼 代碼如下:

  {"sentiment":4,"word":"fantastic"}

  到

   代碼如下:

  

  

  4

  fantastic

  

  注意split函數在lua中不存在,但是你可以參照這裡 but you can use this one.

  現在,這個轉換是個手動過程,我們需要知道json的字段名稱,但是我們也可以采用自動的方式分配json對象名稱為指定的xml標簽。

  既然我們已經轉化為xml了,我們想要給輸出的xml添加額外的字段,比如時間戳怎麼處理呢?

  添加一個時間戳

  在lua代碼塊中,你有整個的lua環境變量可以自由使用,因此我們使用os模塊來獲取當前時間。

  我們僅需在ngx.say行之前添加下面幾行。

  代碼如下:

  require("os")

  resp

copyright © 萬盛學電腦網 all rights reserved