Lua 가 Nginx 에서 의 응용

12420 단어 luanginx
판 호 백 과학원 에 선발 되 었 다.
Nginx 표준 모듈 과 설정 이 시스템 요구 에 유연 하 게 적응 하지 못 할 경우 Lua 확장 과 맞 춤 형 Nginx 서 비 스 를 고려 할 수 있 습 니 다.OpenResty 는 대량의 우수한 Lua 라 이브 러 리, 제3자 모듈 을 통합 하여 초고 속 병행, 확장 성 이 높 은 웹 서 비 스 를 편리 하 게 구축 할 수 있 기 때문에 OpenResty 가 제공 하 는 lua - nginx - module 방안 을 선택 합 니 다.
Lua 환경 설치
lua - nginx - module 은 LuaJIT 와 ngx 에 의존 합 니 다.devel_kit。LuaJIT 설치 필요, ngxdevel_kit 는 원본 패키지 만 다운로드 하고 Nginx 컴 파일 시 ngx 를 지정 합 니 다.devel_kit 디 렉 터 리.
시스템 의존 라 이브 러 리
우선 시스템 에 다음 의존 라 이브 러 리 가 설치 되 어 있 는 지 확인 하 십시오.
$ yum install readline-devel pcre-devel openssl-devel gcc

LuaJIT 설치
우선, LuaJIT 환경 을 설치 하고 다음 과 같다.
$ wget http://luajit.org/download/LuaJIT-2.0.5.tar.gz
$ tar zxvf LuaJIT-2.0.5.tar.gz
$ cd LuaJIT-2.0.5
$ make install
#     
==== Successfully installed LuaJIT 2.0.5 to /usr/local ====

LuaJIT 와 관련 된 환경 변 수 를 설정 합 니 다.
$ export LUAJIT_LIB=/usr/local/lib
$ export LUAJIT_INC=/usr/local/include/luajit-2.0
$ echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local_lib.conf
$ ldconfig

관련 모듈 다운로드
다운로드 ngxdevel_kit 소스 패키지, 다음 과 같 습 니 다:
$ wget https://github.com/simpl/ngx_devel_kit/archive/v0.3.0.tar.gz
$ tar zxvf v0.3.0.tar.gz
#        
ngx_devel_kit-0.3.0

다음은 Lua 모듈 lua - nginx - module 소스 패 키 지 를 다운로드 하여 Nginx 컴 파일 을 준비 합 니 다.
$ wget https://github.com/openresty/lua-nginx-module/archive/v0.10.10.tar.gz
$ tar zxvf v0.10.10.tar.gz
#        
lua-nginx-module-0.10.10

Lua 모듈 불 러 오기
Nginx 1.9 버 전 후 모듈 을 동적 으로 불 러 올 수 있 지만 버 전이 너무 낮 아서 Nginx 를 다시 컴 파일 할 수 밖 에 없습니다.Nginx 소스 패키지 다운로드 및 압축 풀기:
$ wget http://nginx.org/download/nginx-1.13.5.tar.gz
$ tar zxvf nginx-1.13.5.tar.gz

Nginx 를 컴 파일 하고 다시 설치 하기:
$ cd nginx-1.13.5
#   --add-module=/usr/src/lua-nginx-module-0.10.10 --add-module=/usr/src/ngx_devel_kit-0.3.0
$ ./configure --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module --with-http_stub_status_module --with-pcre --add-module=/usr/src/lua-nginx-module-0.10.10 --add-module=/usr/src/ngx_devel_kit-0.3.0
$ make
$ make install
#         
$ nginx -v

Nginx 환경 설정
현재 Nginx 만 설정 하면 Lua 스 크 립 트 를 삽입 할 수 있 습 니 다.우선 http 부분 에 Lua 모듈 과 제3자 라 이브 러 리 경 로 를 설정 합 니 다.
#     (cjson)  luajit-2.0/lib
lua_package_path '/home/www/lua/?.lua;;';
lua_package_cpath '/usr/local/include/luajit-2.0/lib/?.so;;';

다음 에 Lua 스 크 립 트 서 비 스 를 설정 합 니 다.
# hello world  
server {
    location /lua_content {
        #   MIME  
        default_type 'text/plain';
        content_by_lua_block {
            ngx.say('Hello,world!')
        }
    }
}

설치 와 설정 이 정상 인지 테스트 하기:
$ service nginx test
$ service nginx reload
#     /lua_content  
Hello,world!

Lua 호출 Nginx
lua - nginx - module 모듈 에 서 는 Lua 에 풍부 한 Nginx 호출 API 를 제공 하 였 으 며, 각 API 는 각자 의 역할 환경 을 가지 고 있 으 며, 상세 한 설명 은 Nginx API for Lua 를 참조 하 시기 바 랍 니 다.여기 에는 기본 API 의 사용 만 열거 되 어 있다.
먼저 Lua 스 크 립 트 서 비 스 를 설정 합 니 다. 설정 파일 은 다음 과 같 습 니 다.
location ~ /lua_api {  
    #     Nginx    
    set $name $host;
    default_type "text/html";  
    #   Lua        
    content_by_lua_file /home/www/nginx-api.lua;  
}

요청 부분
  • ngx.var
  • ngx.var.var_name 형식 으로 Nginx 변수 값 을 가 져 오 거나 설정 할 수 있 습 니 다. 예 를 들 어 requesturi, host, request 등.
    -- ngx.say    
    ngx.say(ngx.var.request_uri)
    ngx.var.name = 'www.fanhaobai.com'
  • ngx.req.get_headers()

  • 이 방법 은 현재 요청 한 헤더 정 보 를 표 형식 으로 되 돌려 줍 니 다.요청 한 헤더 정보 보기:
    ngx.say('Host : ', ngx.req.get_headers().host, '
    ') for k,v in pairs(ngx.req.get_headers()) do if type(v) == "table" then ngx.say(k, " : ", table.concat(v, ","), '
    ') else ngx.say(k," : ", v, '
    ') end end

    물론, ngx. req. set 를 통 해헤더 () 도 헤더 정 보 를 설정 할 수 있 습 니 다.
    ngx.req.set_header("Content-Type", "text/html")
  • ngx.req.get_uri_args()

  • 이 방법 은 현재 요청 한 모든 GET 인 자 를 표 형식 으로 되 돌려 줍 니 다.요청 query ?name=fhb 의 GET 인자 보기:
    ngx.say('name : ', ngx.req.get_uri_args().name, '
    ') for k,v in pairs(ngx.req.get_uri_args()) do if type(v) == "table" then ngx.say(k, " : ", table.concat(v, ","), '
    ') else ngx.say(k," : ", v, '
    ') end end

    마찬가지 로 ngx. req. set 를 통 해uri_args () 는 요청 한 모든 GET 인 자 를 설정 합 니 다.
    ngx.req.set_uri_args({name='fhb'}) --{name='fhb'}   query  name=fhb
  • get_post_args()

  • 이 방법 은 현재 요청 한 모든 POST 인 자 를 표 형식 으로 되 돌려 줍 니 다. POST 데 이 터 는 application / x - ww - form - urlencoded 형식 이 어야 합 니 다.요청 curl --data 'name=fhb' localhost/lua_api 의 POST 인자 보기:
    --     body 
    ngx.req.read_body()
    ngx.say('name : ', ngx.req.get_post_args().name, '
    ') for k,v in pairs(ngx.req.get_post_args()) do if type(v) == "table" then ngx.say(k, " : ", table.concat(v, ","), '
    ') else ngx.say(k," : ", v, '
    ') end end

    ngx. req. get 통과 하기body_data () 방법 은 해석 되 지 않 은 요청 body 내용 문자열 을 가 져 올 수 있 습 니 다.
  • ngx.req.get_method()

  • 요청 한 대문자 형식의 요청 방식 을 가 져 옵 니 다. ngx. req. setmethod () 는 요청 방식 을 설정 할 수 있 습 니 다.예 를 들 면:
    ngx.say(ngx.req.get_method())

    응답 부분
  • ngx.header
  • ngx.header.header_name 형식 으로 응답 헤드 정 보 를 얻 거나 설정 합 니 다.다음 과 같다.
    ngx.say(ngx.header.content_type)
    ngx.header.content_type = 'text/plain'
  • ngx.print()

  • ngx. print () 방법 은 응답 body 에 지정 한 내용 을 채 웁 니 다.다음 과 같다.
    ngx.print(ngx.header.content_type)
  • ngx.say()

  • 위 에서 사용 한 바 와 같이, ngx. say () 방법 은 ngx. print () 방법 과 같 으 며, 나중에 줄 바 꿈 자 를 추가 할 뿐 입 니 다.
  • ngx.exit()

  • 어떤 상태 코드 로 응답 내용 을 되 돌려 줍 니 다. 상태 코드 상수 대응 관 계 는 HTTP status constants 부분 을 볼 수 있 고 디지털 형식의 상태 코드 도 지원 합 니 다.
    ngx.exit(403)
  • ngx.redirect()

  • 현재 요청 한 url 로 다시 설정 합 니 다. 응답 상태 코드 선택 가능 목록 은 301, 302 (기본 값), 303, 307 입 니 다.
    ngx.redirect('http://www.fanhaobai.com')

    기타
  • ngx.re.match

  • 이 방법 은 정규 표현 식 일치 방법 을 제공 합 니 다.GET 인자 의 숫자 와 일치 하 는 요청 ?name=fhb&age=24:
    local m, err = ngx.re.match(ngx.req.set_uri_args, "[0-9]+")
    if m then
        ngx.say(m[0])
    else
        ngx.say("match not found")
    end
  • ngx.log()

  • 이 방법 을 통 해 내용 을 Nginx 로그 파일 에 기록 할 수 있 습 니 다. 로그 파일 단 계 는 log 단계 와 일치 해 야 합 니 다.
  • ngx.md5() | ngx.encode_base64() | ngx.decode_base64()

  • 그것들 은 모두 문자열 인 코딩 방식 이다.ngx. md5 () 는 문자열 을 md5 암호 화 처리 할 수 있 으 며, ngx. encodebase 64 () 는 문자열 base 64 인 코딩, ngx. decodebase 64 () 는 base 64 디 코딩 입 니 다.
    Nginx 에 Lua 삽입
    Lua 에서 Nginx 의 API 를 어떻게 호출 하여 Nginx 의 기능 을 확장 하거나 맞 추 는 지 설명 합 니 다. 그러면 작 성 된 Lua 스 크 립 트 는 Nginx 에서 어떻게 실 행 됩 니까?사실 Nginx 는 모듈 명령 형식 을 통 해 11 개의 처리 단계 에서 삽입 식 처 리 를 하고 명령 은 http, server, server if, location, location if 라 는 몇 가지 범 위 를 덮어 씁 니 다.
    모듈 명령 어 목록
    기본 적 인 Lua 모듈 명령 만 열거 하고 더 많은 정 보 는 Directives 부분 을 참고 합 니 다.
    지령
    소재 단계
    사용 범위
    설명 하 다.
    init_by_luainit_by_lua_file
    프로필 불 러 오기
    http
    전역 설정 초기 화 에 사용 할 수 있 습 니 다.
    set_by_luaset_by_lua_file
    rewrite
    serverlocationlocation if
    복잡 한 논리의 변수 할당, 주 의 는 차단 되 어 있 습 니 다.
    rewrite_by_luarewrite_by_lua_file
    rewrite
    httpserverlocationlocation if
    복잡 한 논리의 퍼 가기 나 재 정립 을 실현 하 다.
    content_by_luacontent_by_lua_file
    content
    locationlocation if
    요청 처리 및 출력 응답
    header_filter_by_luaheader_filter_by_lua_file
    응답 헤드 정보 필터
    httpserverlocationlocation if
    응답 헤더 정보 설정
    body_filter_by_luabody_filter_by_lua_file
    출력 필터
    httpserverlocationlocation if
    출력 을 필터 하거나 수정 합 니 다.
    사용 명령
    명령 마다 *_lua*_lua_file 두 개의 명령 이 있 고 *_lua 명령 후 Lua 코드 블록 이 며 *_lua_file 명령 후 Lua 스 크 립 트 파일 경로 임 을 알 수 있 습 니 다.다음은 *_lua 명령 에 대해 서 만 설명 할 것 이다.
  • init_by_lua

  • 이 명령 은 Nginx 의 Master 프로 세 스 가 설정 을 불 러 올 때 실 행 됩 니 다. 따라서 Lua 모듈 초기 화 작업 을 완료 할 수 있 습 니 다. Worker 프로 세 스 도 이 를 계승 합 니 다.nginx.conf 프로필 의 http 부분 에 다음 코드 를 추가 합 니 다.
    --   worker       
    lua_shared_dict shared_data 1m;  
    init_by_lua_file /usr/example/lua/init.lua;
    init.lua 스 크 립 트 초기 화:
    local cjson = require 'cjson'
    local redis = require 'resty.redis'
    local shared_data = ngx.shared.shared_data
  • set_by_lua

  • 우리 가 set 명령 을 직접 사용 하면 복잡 한 변수 할당 논 리 를 실현 하기 어렵 고 setby_lua 모듈 명령 으로 이 문 제 를 해결 할 수 있 습 니 다.nginx.conf 프로필 location 부분 은 다음 과 같 습 니 다.
    location /lua {
        set_by_lua_file $num /home/www/set.lua;
        default_type 'text/html';
        echo $num;
    }
    set.lua 스 크 립 트 내용 은:
    local uri_args = ngx.req.get_uri_args()
    local i = uri_args.a or 0
    local j = uri_args.b or 0
    return i + j

    상기 할당 논리, query ?a=10&b=2 를 요청 할 때 응답 내용 은 12 입 니 다.
  • rewrite_by_lua

  • 내부 URL 재 작성 이나 외부 재 설정 을 실현 할 수 있 습 니 다.nginx.conf 설정 은 다음 과 같 습 니 다.
    location /lua {
        default_type "text/html";
        rewrite_by_lua_file /home/www/rewrite.lua;
    }
    rewrite.lua 스 크 립 트 내용:
    if ngx.req.get_uri_args()["type"] == "app" then
        ngx.req.set_uri("/m_h5", false);
    end
  • access_by_lua

  • 접근 권한 제어 에 사용 합 니 다.예 를 들 어 신분 표 지 를 가 진 사용자 만 접근 할 수 있 습 니 다. nginx.conf 설정 은 다음 과 같 습 니 다.
    location /lua {  
        default_type "text/html";
        access_by_lua_file /home/www/access.lua;
    }  
    access.lua 스 크 립 트 내용 은:
    if ngx.req.get_uri_args()["token"] == "fanhb" then
        return ngx.exit(403)
    end
  • content_by_lua

  • 이 명령 은 Lua 에서 Nginx 부분 을 호출 하여 응답 내용 을 출력 하 는 데 사용 되 었 습 니 다.
    케이스
    접근 권한 제어
    Lua 모듈 을 사용 하여 본 사이트 의 ES 서 비 스 를 수신 조작 으로 제어 합 니 다. 즉, 수신 IP 가 아 닌 조회 조작 만 할 수 있 습 니 다.nginx.conf 설정 은 다음 과 같 습 니 다.
    location / {
        set $allowed '115.171.226.212';
        access_by_lua_block {
            if ngx.re.match(ngx.req.get_method(), "PUT|POST|DELETE") and not ngx.re.match(ngx.var.request_uri, "_search") then
            start, _ = string.find(ngx.var.allowed, ngx.var.remote_addr)
            if not start then
            ngx.exit(403)
            end
        end
        }
        
        proxy_pass http://127.0.0.1:9200$request_uri;
    }

    액세스 주파수 제어
    Nginx 프로필 의 location 부분 에 Lua 스 크 립 트 기본 매개 변 수 를 설정 하고 Lua 모듈 명령 을 설정 합 니 다.
    default_type "text/html";
    set rate_per 300
    access_by_lua_file /home/www/access.lua;

    Lua 스 크 립 트 는 주파수 제어 논 리 를 실현 하고 Redis 를 사용 하여 단위 시간 내 접근 횟수 를 캐 시 합 니 다. key 는 uri 를 방문 하여 token 을 연결 한 후의 md5 값 입 니 다.구체 적 인 내용 은 다음 과 같다.
    local redis = require "resty.redis"
    local red = redis:new()
    
    local limit = tonumber(ngx.var.rate_per) or 200
    local expire_time = tonumber(ngx.var.rate_expire) or 1000
    local key = "rate.limit:string:"
    
    red:set_timeout(500)
    local ok, err = red:connect("www.fanhaobai.com", 6379)
    if not ok then
        ngx.log(ngx.ERR, "failed to connect redis: " .. err)
        return
    end
    
    key = key .. ngx.md5(ngx.var.request_uri .. (ngx.req.get_uri_args()['token'] or ngx.req.get_post_args()['token']))
    local times, err = red:incr(key)
    if not times then
        ngx.log(ngx.ERR, "failed to exec incr: " .. err)
        return
    elseif times == 1 then
        ok, err = red:expire(key, expire_time)
        if not ok then
            ngx.log(ngx.ERR, "failed to exec expire: " .. err)
            return
        end
    end
    
    if times > limit then
        return ngx.exit(403)
    end
    
    return

    관련 글 »
  • 루 아의 세계 진입 (2017 - 09 - 03)
  • Lua 가 Redis 에서 의 응용 (2017 - 09 - 04)
  • 좋은 웹페이지 즐겨찾기