openresty+orange+nginx+ueditor 修復文件圖片上傳

最近公司開發文章功能,使用了ueditor

前端使用 vuejs

後臺使用php

服務器 openresty+orange+nginx+centos

下面是nginx的配置

server {
    listen 80;
    server_name baidu.com;
    proxy_read_timeout 600;
    # 秒
    location = /favicon.ico {
        log_not_found off;
        access_log off;
    }
    location /log {
        content_by_lua_block {
            local logger = require("api.logger")
            logger:log()
        }
    }
    location ^~ /testEvent/ {
        content_by_lua_block {
            ngx.log(ngx.INFO,' ',"testEvent")
        }
    }
    location ^~ /callback/ {
        set $origin 'https://www.baidu.com';
        if ( $http_origin ~ ^.+\.baidu.com) {
            set $origin *;
        }

                #ueditor 需要配置 add_header Access-Control-Allow-Origin *
        add_header Access-Control-Allow-Origin $http_origin;

        add_header Access-Control-Allow-Credentials true;

                #ueditor 需要配置 X_Requested_With,x_requested_with
        add_header Access-Control-Allow-Headers X-Requested-With,X_Requested_With,x_requested_with;

        add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
        set $origin $http_referer;
        set $upstream_url 'http://baidu_upstream';
        content_by_lua_block {
            local callback = require("api.callback")
            callback:run()
        }
    }
    location / {
        set $origin 'https://www.baidu.com';
        if ( $http_origin ~ ^.+\.baidu.com) {
            set $origin $http_origin;
        }
        add_header Access-Control-Allow-Origin $origin;
        add_header Access-Control-Allow-Credentials true;
        add_header Access-Control-Allow-Headers X-Requested-With;
        add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
        set $upstream_url 'http://baidu_upstream';
        rewrite_by_lua_block {
            local orange = context.orange
            orange.redirect()
            orange.rewrite()
        }
        access_by_lua_block {
            local orange = context.orange
            orange.access()
        }
        header_filter_by_lua_block {
            local orange = context.orange
            orange.header_filter()
        }
        body_filter_by_lua_block {
            local orange = context.orange
            orange.body_filter()
        }
        log_by_lua_block {
            local orange = context.orange
            orange.log()
        }
        content_by_lua_block {
            local gateway = require("api.gateway")
            gateway:run()
        }
    }
    location ~ /get_content/(.*) {
        internal;
        set $upstream_host $host;
        set $upstream_url $arg_upstreamUrl;
        # proxy
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Scheme $scheme;
        proxy_set_header Host $upstream_host;
        proxy_pass $upstream_url/$1$is_args$args;
    }
    location /robots.txt {
        return 200 'User-agent: *\nDisallow: /';
    }
}

lua的callback.lua配置

--
-- Created by IntelliJ IDEA.
-- User: Administrator
-- Date: 2018/9/19
-- Time: 11:15
-- To change this template use File | Settings | File Templates.
--

local type = type
local json = require("orange.utils.json")

--升級版(能處理content-type=multipart/form-data的表單):
local function explode ( _str,seperator )
    local pos, arr = 0, {}
    for st, sp in function() return string.find( _str, seperator, pos, true ) end do
        table.insert( arr, string.sub( _str, pos, st-1 ) )
        pos = sp + 1
    end
    table.insert( arr, string.sub( _str, pos ) )
    return arr
end

--圖片上傳參數修復
local args = {}
local file_args = {}
local is_have_file_param = false
local function init_form_args()
    local receive_headers = ngx.req.get_headers()
    local request_method = ngx.var.request_method
    if "GET" == request_method then
        args = ngx.req.get_uri_args()
    elseif "POST" == request_method then
        ngx.req.read_body()
        --判斷是否是multipart/form-data類型的表單
        if string.sub(receive_headers["content-type"],1,20) == "multipart/form-data;" then
            is_have_file_param = true
            content_type = receive_headers["content-type"]
            --body_data可是符合http協議的請求體,不是普通的字符串
            body_data = ngx.req.get_body_data()
            --請求體的size大於nginx配置裏的client_body_buffer_size,則會導致請求體被緩衝到磁盤臨時文件裏,client_body_buffer_size默認是8k或者16k
            if not body_data then
                local datafile = ngx.req.get_body_file()
                if not datafile then
                    error_code = 1
                    error_msg = "no request body found"
                else
                    local fh, err = io.open(datafile, "r")
                    if not fh then
                        error_code = 2
                        error_msg = "failed to open " .. tostring(datafile) .. "for reading: " .. tostring(err)
                    else
                        fh:seek("set")
                        body_data = fh:read("*a")
                        fh:close()
                        if body_data == "" then
                            error_code = 3
                            error_msg = "request body is empty"
                        end
                    end
                end
            end
            local new_body_data = {}
            --確保取到請求體的數據
            if not error_code then
                local boundary = "--" .. string.sub(receive_headers["content-type"],31)
                local body_data_table = explode(tostring(body_data),boundary)
                local first_string = table.remove(body_data_table,1)
                local last_string = table.remove(body_data_table)
                for i,v in ipairs(body_data_table) do
                    local start_pos,end_pos,capture,capture2 = string.find(v,'Content%-Disposition: form%-data; name="(.+)"; filename="(.*)"')
                    --普通參數
                    if not start_pos then
                        local t = explode(v,"rnrn")
                        local temp_param_name = string.sub(t[1],41,-2)
                        local temp_param_value = ""
                        if t[2] then
                            temp_param_value = string.sub(t[2],1,-3)
                        end
                        args[temp_param_name] = temp_param_value
                    else
                        --文件類型的參數,capture是參數名稱,capture2是文件名
                        file_args[capture] = capture2
                        table.insert(new_body_data,v)
                    end
                end
                table.insert(new_body_data,1,first_string)
                table.insert(new_body_data,last_string)
                --去掉app_key,app_secret等幾個參數,把業務級別的參數傳給內部的API
                body_data = table.concat(new_body_data,boundary)--body_data可是符合http協議的請求體,不是普通的字符串
                file_args[body_data] = body_data
            end
        else
            args = ngx.req.get_post_args()
        end
    end
end

local _M = {
}

function _M:check()
    local uri = ngx.var.uri;
    local urls = {
        '/callback/hello/hello/ueditorUpload',
    }

    for k,v in pairs(urls) do
        if(v == uri) then
            return true
        end
    end

    return false
end
function _M:run()

    ngx.log(ngx.INFO,'callback  ',ngx.var.uri )
    ngx.log(ngx.INFO,'callback  ',ngx.var.args)

    if self.check() == false then
        ngx.exit(404)
    end

    --    POST參數配置
    ngx.req.read_body()
    local postParam,err = ngx.req.get_post_args()
    ngx.log(ngx.INFO,'post ',json.encode(postParam))

    local post = ''

    local postParamString = json.encode(postParam)
    --如果是微信支付回調
    if string.find(postParamString,"[CDATA[weixin]") ~= nil then
        for i,v in pairs(postParam) do
            post = i
        end
    end
    --如果是支付寶支付回調
    if string.find(postParamString,"seller_id") ~= nil or string.find(postParamString,"trade_status") ~= nil then
        postParam['api_param'] = postParamString
    end
    --如果是上傳文件回調
    if string.find(ngx.var.uri,"ueditorUpload") ~= nil then
        postParam = {}
    end

    ngx.log(ngx.INFO,'post ',json.encode(postParam))

    if postParam['api_param'] then
        local param = json.decode(postParam['api_param'])
        if type(param) == 'table' then
            for i,v in pairs(param) do
                if type(v) == 'table' then
                    param[i] = json.encode(v)
                end
            end
            post = ngx.encode_args(param)
        end
    end
    --如果是上傳文件回調
    if string.find(ngx.var.uri,"ueditorUpload") ~= nil then
        init_form_args()
        if is_have_file_param then
            post = file_args[body_data]
        end
    end
    ngx.log(ngx.INFO,'post ',post)



    local uri = string.sub(ngx.var.uri,10,string.len(ngx.var.uri))
    --    GET參數 和url配置
    local host = "/get_content"..uri
    ngx.log(ngx.INFO,'uri ',uri)

    local methods = ngx.HTTP_POST
    if uri ==  '/MP_verify_jm2DDTI9M1Wtswwy.txt' then
        methods = ngx.HTTP_GET
    end
    if postParam['action'] then
        local action =  string.gsub(postParam['action'], '%.', function(h) return '/' end)
        ngx.log(ngx.INFO,'action1 ',action)
        if string.find(action,"/") == 1 then
            action = string.sub(action,2,string.len(action))
            ngx.log(ngx.INFO,'action2 ',action)
        end
        host = host..action
    end
    host = host..ngx.var.is_args
    local link = '&'
    if ngx.var.is_args ~= '?' then
        link = '?'
    else
        host = host..ngx.var.args
    end
    host = host..link..'upstreamUrl='..ngx.var.upstream_url
    ngx.log(ngx.INFO,'host ',host)

--    發起請求
--    ngx.log(ngx.INFO,'Content-Type ', ngx.req.raw_header())
    ngx.req.clear_header('Accept-Encoding')
    local res = ngx.location.capture(host,{
        method = methods,
        body     =  post,
    })

    ngx.header['Content-Type'] = res.header["Content-Type"]

    ngx.header['location'] = res.header["location"]
    --   修復php sessionid 丟失問題
    if not ngx.var.cookie_session then
        if res.header["Set-Cookie"] then
            ngx.header["Set-Cookie"] = res.header["Set-Cookie"];
        end
    end
    ngx.status = res.status
    ngx.say(res.body)
    ngx.exit(200)
end




return _M

 

參考:https://www.cnblogs.com/wangzhisdu/p/7771310.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章