UEditor+nodejs+seaweedfs圖片服務器搭建

參考鏈接:
http://blog.coinidea.com/web%E5%BC%80%E5%8F%91/nodejs-1161.html

1. UEditor+nodejs圖片上傳
UEditor是百度開源的富文本編輯器,功能比較強大。
下載地址是:http://ueditor.baidu.com/website/download.html
目前提供:PHP、ASP、.Net、JSP版本。UEditor主要是以前端HTML、CSS、JS為主的,之所以按各種動態(tài)語言再細分版本,我的理解是主要是在圖片上傳這一涉及到與服務器交互的功能上。
在眾多版本中,沒有提供nodejs的版本,下面將介紹如何用PHP版本的UEditor改造成nodejs版本的UEditor。
咨詢查看PHP版本的所有請求,發(fā)現(xiàn)action參數(shù)值包括config(配置文件)、uploadimage(圖片上傳)、listimage(在線管理)、catchimage(抓取圖片),所以只需要重寫這4個請求就基本上實現(xiàn)了我們的需求。
1.1 修改UEditor的ueditor.config.js的serverUrl屬性:

serverUrl: '/ue/uploads'

1.2 將ueditor/php/config.json文件名修改為config.js并移動到ueditor目錄下。
1.3 接下來主要在nodejs端編寫對應的四個action就好,圖片上傳使用了connect-busboy中間件。代碼如下:

// 圖片上傳
var path = require('path');
var uploadsPath = path.resolve('public/uploads') + '/';//存儲圖片的路徑
var busboy = require('connect-busboy');
app.use(busboy({
    limits: {
        fileSize: 10 * 1024 * 1024 // 10MB
    }
}));
var action = {
    /// 上傳圖片
    uploadimage: function (req, res) {
        var fstream;
        req.pipe(req.busboy);
        req.busboy.on('file', function (fieldname, file, filename, encoding, mimetype) {
            var filesize = 0;
            var ext = path.extname(filename);
            var newFilename = (new Date() - 0) + ext;
            fstream = fs.createWriteStream(uploadsPath + newFilename);
            file.on('data', function (data) {
                filesize = data.length;
            });
            fstream.on('close', function () {
                console.log(JSON.stringify({
                    "originalName": filename,
                    "name": newFilename,
                    "url": '/uploads/' + newFilename,
                    "type": ext,
                    "size": filesize,
                    "state": "SUCCESS"
                }));
                res.send(JSON.stringify({
                    "originalName": filename,
                    "name": newFilename,
                    "url": '/uploads/' + newFilename,
                    "type": ext,
                    "size": filesize,
                    "state": "SUCCESS"
                }));
            });
            file.pipe(fstream);
        });
    },
    /// 獲取配置文件
    config: function (req, res) {
        return res.redirect('/js/UEditor/config.js');
    },
    /// 在線管理
    listimage: function (req, res) {
        fs.readdir(uploadsPath, function (err, files) {
            var total = 0, list = [];
            files.sort().splice(req.query.start, req.query.size).forEach(function (a, b) {
                /^.+.\..+$/.test(a) &&
                list.push({
                    url: '/uploads/' + a,
                    mtime: new Date(fs.statSync(uploadsPath + a).mtime).getTime()
                });
            });
            total = list.length;
            res.json({state: total === 0 ? 'no match file' : 'SUCCESS', list: list, total: total, start: req.query.start});
        });
    },
    /// 抓取圖片(粘貼時將圖片保存到服務端)
    catchimage: function (req, res) {
        var list = [];
        req.body.source.forEach(function (src, index) {
            http.get(src, function (_res) {
                var imagedata = '';
                _res.setEncoding('binary');
                _res.on('data', function (chunk) {
                    imagedata += chunk
                });
                _res.on('end', function () {
                    var pathname = url.parse(src).pathname;
                    var original = pathname.match(/[^/]+\.\w+$/g)[0];
                    var suffix = original.match(/[^\.]+$/)[0];
                    var filename = Date.now() + '.' + suffix;
                    var filepath = uploadsPath + 'catchimages/' + filename;
                    fs.writeFile(filepath, imagedata, 'binary', function (err) {
                        list.push({
                            original: original,
                            source: src,
                            state: err ? "ERROR" : "SUCCESS",
                            title: filename,
                            url: '/uploads/catchimages/' + filename
                        });
                    })
                });
            })
        });
        var f = setInterval(function () {
            if (req.body.source.length === list.length) {
                clearInterval(f);
                res.json({state: "SUCCESS", list: list});
            }
        }, 50);
 
    }
};
app.get('/ue/uploads',function (req, res) {
    action[req.query.action](req, res);
});
app.post('/ue/uploads', function (req, res) {
    action[req.query.action](req, res);
});

以上主要參考了博客:http://www.xiaoboy.com/detail/1341545081.html
2. GoLang的安裝與配置
1中UEditor的圖片上傳到哪兒nodejs服務器中的/public/uploads/文件夾中,如果需要高存儲、可移植、可擴展等特性的圖片服務器,則需要配置專門的服務器。本文選用的是開源的圖片(文件)分布式服務器seaweedfs。
Github地址:https://github.com/chrislusf/seaweedfs
該服務器使用GoLang編寫,所以需要安裝配置GoLang。中國的下載地址:http://www.golangtc.com/download,根據(jù)自己的操作系統(tǒng)選擇特定的包下載即可。本文演示的windows7 x64下載安裝。傻瓜式安裝好之后,需要配置一下環(huán)境變量:

GOROOT=D:\Go16
GOPATH=D:\ImageServer\seaweedfs
PATH=D:\Go16\bin

GOPATH環(huán)境變量,這個變量很重要,我自己寫的代碼要放到這個變量中配置的目錄中,go編譯器才會找到并編譯
3. seaweedfs的編譯運行
Github上吧seaweedfs的代碼clone下來,然后安裝makefile中的執(zhí)行也可以直接直接makefile。在seaweedfs中執(zhí)行控制臺:

go clean -i -v ./go/weed/
#rm –f weed #for linux
go get -v –d ./go/weed
go build -v -o weed ./go/weed

其中在get依賴的時候有可能有些依賴包不能下載,需要自己手動下載,放入:\seaweedfs\src目錄中。
推薦一個go下載包地址:https://gopm.io/download?pkgname=golang.org/x/net
Buid之后會在seaweedfs中生成一個weed,也可以將其改名為weed.exe。這個時候就可以啟動weed。以本機為演示:

weed master

weed volume –dir=”./tmp/data1” –max=5 –mserver=”localhost:9333” –port=8080 &
[![image](http://upload-images.jianshu.io/upload_images/13720662-4e045e11d550fd66.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240 "image003")](http://devhu-wordpress.stor.sinaapp.com/uploads/2016/05/image0031.png) 

按照github的描述上傳、下載圖片都沒有問題。至此基本的圖片服務器搭建完成。

修改nodejs的圖片上傳代碼如下:

// 圖片上傳
var path = require('path');
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();
function curlPostAssign(res, filepath, filename, filesize) {
    request.post(config.url_image + 'dir/assign',{},
        function (error, response, body) {
            if (!error && response.statusCode == 200) {
                assign = eval('(' + body + ')');
                var result = {};
                result.res = res;
                result.json = JSON.stringify({
                    "originalName": filename,
                    "name": assign.fid,
                    "url": '/res?fid=' + assign.fid,
                    "type": ext,
                    "size": filesize,
                    "state": "SUCCESS"
                });
                curlPostWrite(assign.fid, filepath, assign.publicUrl, result);
                var ext = path.extname(filename);
            }else{
                console.log("Image server assign error...")
            }
        });
}
function curlPostWrite(fid, tmp_file, publicUrl, result) {
    var files = [
        {urlKey: "file1", urlValue: tmp_file}
    ]
    var options = {
        host: publicUrl.split(":")[0] ,
        port: publicUrl.split(":")[1] ,
        method: "POST",
        path: "/" + fid
    }
 
    var req = http.request(options, function(res){
        //res.setEncoding("utf8");
        res.on("data", function(chunk){
            //console.log("BODY:" + chunk);
        })
    })
 
    req.on('error', function(e){
        console.log('problem with request:' + e.message);
        console.log(e);
    })
    postfile.postFile(files, req, result);
 
}
var action = {
    /// 上傳圖片
    uploadimage: function(req, res) {
       curlPostAssign(res, req.files.upfile.path, req.files.upfile.originalFilename, req.files.upfile.size);
    },
    /// 獲取配置文件
    config: function (req, res) {
        return res.redirect('/js/UEditor/config.js');
    },
    /// 在線管理
    listimage: function (req, res) {
        fs.readdir(uploadsPath, function (err, files) {
            var total = 0, list = [];
            files.sort().splice(req.query.start, req.query.size).forEach(function (a, b) {
                /^.+.\..+$/.test(a) &&
                list.push({
                    url: '/uploads/' + a,
                    mtime: new Date(fs.statSync(uploadsPath + a).mtime).getTime()
                });
            });
            total = list.length;
            res.json({state: total === 0 ? 'no match file' : 'SUCCESS', list: list, total: total, start: req.query.start});
        });
    },
    /// 抓取圖片(粘貼時將圖片保存到服務端)
    catchimage: function (req, res) {
        var list = [];
        req.body.source.forEach(function (src, index) {
            http.get(src, function (_res) {
                var imagedata = '';
                _res.setEncoding('binary');
                _res.on('data', function (chunk) {
                    imagedata += chunk
                });
                _res.on('end', function () {
                    var pathname = url.parse(src).pathname;
                    var original = pathname.match(/[^/]+\.\w+$/g)[0];
                    var suffix = original.match(/[^\.]+$/)[0];
                    var filename = Date.now() + '.' + suffix;
                    var filepath = uploadsPath + 'catchimages/' + filename;
                    fs.writeFile(filepath, imagedata, 'binary', function (err) {
                        list.push({
                            original: original,
                            source: src,
                            state: err ? "ERROR" : "SUCCESS",
                            title: filename,
                            url: '/uploads/catchimages/' + filename
                        });
                    })
                });
            })
        });
        var f = setInterval(function () {
            if (req.body.source.length === list.length) {
                clearInterval(f);
                res.json({state: "SUCCESS", list: list});
            }
        }, 50);
 
    }
};
app.get('/ue/uploads',multipartMiddleware, function (req, res) {
    action[req.query.action](req, res);
});
app.post('/ue/uploads',multipartMiddleware, function (req, res) {
    action[req.query.action](req, res);
});

運行效果:


image

參考鏈接:
http://blog.coinidea.com/web%E5%BC%80%E5%8F%91/nodejs-1161.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,632評論 19 139
  • 1、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明AI閱讀 16,211評論 3 119
  • 說起北京,我更愿意稱其為“北平”、“京城”,一直想親眼看看白雪皚皚的皇城故宮,感受流傳千年的京城風貌。 又一次冬季...
    筱熙Cynthia閱讀 966評論 0 4
  • 事實證明,在人際交往和自己生活方面,我還是一如既往的內(nèi)心羞澀和自卑纏繞。抑郁期的到來。
    飛魚據(jù)說是我閱讀 352評論 0 0
  • 作為一名剛剛刷完最新全國文綜卷的準高三狗,此刻內(nèi)心的委屈和崩潰此起彼伏。 這個軟件是很久以前無意中在雜志推薦上看到...
    孤燈隔遠汀閱讀 209評論 0 0

友情鏈接更多精彩內(nèi)容