lua - resty - upload 기반 간단 한 파일 업로드 서비스 구현

오늘 은 lua - resty - upload 모듈 을 알 아 보고 lua - resty - upload 모듈 을 바탕 으로 기본 적 인 폼 파일 업로드 서 비 스 를 간단하게 실현 했다.
lua - resty - upload github 에 있 는 항목 주 소 는:https://github.com/openresty/lua-resty-upload
실현 을 통 해 알 수 있 듯 이 사실 upload 서비스의 실현 은 비교적 간단 하 다. 하나의 소스 파일 인 lualib / resty / upload. lua 만 있 고 전체 코드 줄 수도 300 줄 밖 에 안 된다.
다음은 파일 을 만들어 서 서 서 비 스 를 올 리 는 과정 을 정리 해 봤 습 니 다.
1. 전단 페이지 는 매우 간단 합 니 다. 바로 input file 의 폼 형식 으로 파일 업 로드 를 촉발 하 는 것 입 니 다. 코드 는 다음 과 같 습 니 다.

html>


    File upload example


    
        select file: 
        
        
    
대응 하 는 my upload. html 파일 은 openresty / nginx / html / 아래 에 배 치 됩 니 다.
2. 파일 업로드 폼 정 보 를 수신 하고 로 컬 경로 에 저장 하 는 lua 코드 를 실현 합 니 다. 코드 는 다음 과 같 습 니 다.
-- myupload.lua

--==========================================
--     
--==========================================

local upload = require "resty.upload"
local cjson = require "cjson"

local chunk_size = 4096
local form, err = upload:new(chunk_size)
if not form then
    ngx.log(ngx.ERR, "failed to new upload: ", err)
    ngx.exit(ngx.HTTP_INTERNAL_SERVER_ERROR)
end

form:set_timeout(1000)

--     split   
string.split = function(s, p)
    local rt= {}
    string.gsub(s, '[^'..p..']+', function(w) table.insert(rt, w) end )
    return rt
end

--         trim
string.trim = function(s)
    return (s:gsub("^%s*(.-)%s*$", "%1"))
end

--         
local saveRootPath = "/home/steven/openresty/nginx/upload/"

--        
local fileToSave

--        
local ret_save = false

while true do
    local typ, res, err = form:read()
    if not typ then
        ngx.say("failed to read: ", err)
        return
    end

    if typ == "header" then
        --      http header
        --            
        local key = res[1]
        local value = res[2]
        if key == "Content-Disposition" then
            --            
            -- form-data; name="testFileName"; filename="testfile.txt"
            local kvlist = string.split(value, ';')
            for _, kv in ipairs(kvlist) do
                local seg = string.trim(kv)
                if seg:find("filename") then
                    local kvfile = string.split(seg, "=")
                    local filename = string.sub(kvfile[2], 2, -2)
                    if filename then
                        fileToSave = io.open(saveRootPath .. filename, "w+")
                        if not fileToSave then
                            ngx.say("failed to open file ", filename)
                            return
                        end
                        break
                    end
                end
            end
        end
    elseif typ == "body" then
        --      http body
        if fileToSave then
            fileToSave:write(res)
        end
    elseif typ == "part_end" then
        --      ,    
        if fileToSave then
            fileToSave:close()
            fileToSave = nil
        end
        
        ret_save = true
    elseif typ == "eof" then
        --       
        break
    else
        ngx.log(ngx.INFO, "do other things")
    end
end

if ret_save then
    ngx.say("save file ok")
end

lualib / resty / upload. lua 소스 코드 를 읽 습 니 다. 이 모듈 은 파일 업로드 요청 을 분석 하 는 과정 에서 유한 상태 기기 와 유사 한 간단 한 알고리즘 을 사용 하여 이 루어 집 니 다. 서로 다른 상태 에서 해당 하 는 handler 로 처리 되 고 지원 하 는 상 태 는 다음 과 같은 상 태 를 포함 합 니 다.
  • STATE_BEGIN (1), 초기 상 태 는 upload: new 실례 화 때 초기 화 되 었 습 니 다. 다음 소스 코드 (메 인 만 유지):
  • function _M.new(self, chunk_size, max_line_size)
        local boundary = get_boundary()
        local sock, err = req_socket()
        local read2boundary, err = sock:receiveuntil("--" .. boundary)
        local read_line, err = sock:receiveuntil("\r
    ")     return setmetatable({         sock = sock,         size = chunk_size or CHUNK_SIZE,         line_size = max_line_size or MAX_LINE_SIZE,         read2boundary = read2boundary,         read_line = read_line,         boundary = boundary,         state = STATE_BEGIN     }, mt) end
  • STATE_READING_HEADER (2) 는 HTTP 헤드 메 시 지 를 분석 하기 시 작 했 습 니 다. 보통 이 단계 에서 파일 이름, boundary 등 정 보 를 분석 하 는 데 사 용 됩 니 다.해당 handler 는 read_header;
  • STATE_READING_BODY (3), HTTP 패 키 지 를 분석 하기 시 작 했 습 니 다. 이 단 계 는 파일 내용 을 읽 는 것 입 니 다.
  • STATE_EOF (4) 는 파일 을 모두 해석 하고 읽 은 후에 이 상태 로 들 어 갑 니 다. 보통 이 단 계 는 파일 이 다 읽 었 음 을 나타 냅 니 다.

  • 이 네 가지 상태의 각각 handler 는:
    state_handlers = {
        read_preamble,
        read_header,
        read_body_part,
        eof
    }

    - 여기 서 주의해 야 할 것 은 단계 / 상태 에 따라 read 가 되 돌아 오 는 구조 가 다 릅 니 다. 예 를 들 어 STATEREADING_HEADER 다음 에 돌아 오 는 구 조 는 "header", {key, value, line} 입 니 다.
    - 업 로드 된 파일 은 로 컬 경로 에 저 장 됩 니 다. /home / steven / openresty / nginx / upload / 아래
    3. nginx. conf 를 설정 하고 location / upfile 을 추가 하여 파일 업로드 액 션 을 받 고 my upload. lua 를 통 해 파일 업로드 내용 을 분석 한 후 로 컬 파일 시스템 에 저장 합 니 다. 다음 과 같 습 니 다.
    http {
        include       mime.types;
        default_type  application/octet-stream;
        sendfile        on;
        keepalive_timeout  65;
    
        server {
            listen       19080;
            server_name  localhost;
            
            location / {
                root   html;
                index  index.html index.htm;
            }
    
            location /upfile {
                content_by_lua_file lua/myupload.lua;
            }
    
            # redirect server error pages to the static page /50x.html
            error_page   500 502 503 504  /50x.html;
            location = /50x.html {
                root   html;
            }
        }
    }

    좋은 웹페이지 즐겨찾기