寫了一個論壇會用到圖片上傳功能, 本來是採用imgur的api來串接,
但後來發現其實其api有所限制,包含短時間不能傳太多, 甚至一個月不能超過幾張,
雖然數量非常大, 到達極限的可能性很低, 但反正手癢,
於是決定簡單寫一個圖片伺服器來解決
首先我定義了這傢伙有以下幾個功能
首先因為我個人比較熟悉node,
所以就直接開始思考要用甚麼node的框架來做,
包含express,Koa,.....等等
其中收api,回傳字串算是比較普遍的功能,所以跳過
接著是圖片存儲以及回傳,這貌似就比較複雜
印象中以前用幾個框架做過
不外乎是引用一個他們公司開發的用於該框架的npm套件,
接著按照文件的說法用個函數,填個設定,填個參數
就可以完成任務。
但問題來了, 我今天只不過是要完成這麼點小事,
有必要引用這些框架來協助開發嗎 ?
感覺結果就是MVC裡,M塞滿了東西,但其他地方空空如也
在強迫症發作下我開始想,
原生node是否也擁有兩個套件來完成對應的這兩件事呢?
一查資料, 還真的有, 我就來用用看吧!
我採用visual studio直接建立一個原生node,
以此避免麻煩的指令輸入。
->點擊空白node.js web 應用
既然要接收圖片=>post圖片過來吧
既然要讓任何人call到我的圖片=>get我的圖片吧
所以一個post 一個get
順手設定跨域許可,讓別台主機可以call你(屏蔽處是設定只允許誰call你)
post用一下api 看起來比較專業
'use strict';
var http = require('http');
var port = process.env.PORT || 1337;
http.createServer(function (req, res) {
res.setHeader('Access-Control-Allow-Origin', /***/ '*');
if (req.method == 'GET') {
}
else if(req.url == '/getImg' && req.method == 'POST') {
}
}).listen(port);
此處要活用之前框架提供的功能帶給我的經驗
總之就是以下三步
我採用 npm install node-static
不廢話,寫程式三步驟=>安裝,複製,貼上
//多引用
var nStatic = require('node-static');
var fileServer = new nStatic.Server('./uploadImg');
//get 裡加
fileServer.serve(req, res);
所以變成以下情況:
'use strict';
var http = require('http');
var nStatic = require('node-static');
//以下決定哪個資料夾當成靜態資料服務器的儲存處,要先建立
var fileServer = new nStatic.Server('./uploadImg');
var port = process.env.PORT || 1337;
http.createServer(function (req, res) {
res.setHeader('Access-Control-Allow-Origin', /*'140.116.*'*/ '*');
if (req.method == 'GET') {
//直接建立靜態server,其可使所有get指令可以直接提取上方選定資料夾中的檔案
//, 且可包含資料夾做分類
fileServer.serve(req, res);
}
else if(req.url == '/getImg' && req.method == 'POST') {
}
}).listen(port);
我採用了 formidable 這個npm 套件
其為原生node存圖片的套件
安裝,複製,貼上 三連招一用
//多引用
var formidable = require('formidable');
var path = require('path');//取得副檔名,改存檔時會用到
var fs = require('fs');//改檔名,因為存下來沒副檔名,檔名也是很長的亂碼
//下面加
略,直接看源碼
else if (req.url == '/getImg' && req.method == 'POST') {
//存下傳來的form
var form = formidable.IncomingForm();
// 設定存哪
form.uploadDir = '.\\uploadImg\\' ;
form.parse(req, function (err, fields, files) {//存檔
// all information of picture are in files.file
//console.log(files)
if (err) { throw err; }
// 如果有存到東西
if (files.file != null) {
//取得原始下載下來的檔案
var oldpath = __dirname + "\\" + files.file.path;
// 取得副檔名,改名用
var extname = path.extname(files.file.name);
// 設定新名子為savedata.xxx
var newpath = __dirname + '\\uploadImg\\savedata' + extname;
//回傳位置就是新名子的位置 前面是網域
var returnpath = 'http:\\127.0.0.1:1337\\savedata' + extname;
//改名,不然本來是亂碼,也沒有附檔名,根本無法讀
fs.rename(oldpath, newpath, function (err) {
if (err) {//錯誤處理
console.log(err.message);
res.end("error");
throw Error("false");
}
//回傳get要call的網址
res.end(returnpath);
});
}
else
res.end("error");
});
}
到上面為止已經完成基本目的,但事實是上面的代碼根本不能用,原因有以下幾點
'use strict';
var http = require('http');
var formidable = require('formidable');
var path = require('path');
var fs = require('fs');
var nStatic = require('node-static');
var fileServer = new nStatic.Server('./uploadImg');
var port = process.env.PORT || 1337;
//共有幾個子資料夾 須先建立,名稱為:0,1,2,3,.....16
const hashnumber = 17;
//伺服器所在網域
const baseURL = 'http://localhost:1337';
http.createServer(function (req, res) {
res.setHeader('Access-Control-Allow-Origin', /*'140.116.*'*/ '*');
if (req.method == 'GET') {
fileServer.serve(req, res);
}
else if (req.url == '/getImg' && req.method == 'POST') {
var form = formidable.IncomingForm();
//隨機數取餘數,得知檔案被分配到哪個資料夾
var random = parseInt(Math.random() * 10000);
var place = (random % hashnumber).toString();
form.uploadDir = '.\\uploadImg\\' + place;
form.parse(req, function (err, fields, files) {
if (err) { throw err; }
if (files.file != null) {
var oldpath = __dirname + "\\" + files.file.path;
// 取得時間,等下加到新檔名
var time = +new Date();
var extname = path.extname(files.file.name);
// 新檔名的path有多分配到的子資料夾,和時間,隨機數,副檔名組成的名稱
var newpath = __dirname + '\\uploadImg\\' + place + '\\' + time + random + extname;
//回傳字串當然要包含子資料夾和新名稱
var returnpath = '\\' + place + '\\' + time + random + extname;
fs.rename(oldpath, newpath, function (err) {
if (err) {
console.log(err.message);
res.end("error");
throw Error("false");
}
res.end(baseURL + returnpath);
});
}
else
res.end("error");
});
}
}).listen(port);
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<title></title>
</head>
<body>
<input type="file" />
<script>
// api
var api = 'http://127.0.0.1:1337/getImg';
$("document").ready(function () {
$('input[type=file]').on("change", function () {
var $files = $(this).get(0).files;
if ($files.length) {
// Reject big files
if ($files[0].size > $(this).data("max-size") * 1024) {
console.log("Please select a smaller file");
return false;
}
var formData = new FormData();
formData.append('file', $files[0]);
var settings = {
"async": true,
"crossDomain": true,
"url": api,
"type": "POST",
'contentType': false, //required
'processData': false, // required
'mimeType': 'multipart/form-data',
'data': formData,
beforeSend: function (xhr) {
},
success: function (res) {
console.log(res);
},
error: function () {
alert("Failed | 上傳失敗");
}
}
$.ajax(settings).done(function (response) {
console.log("Done | 完成");
});
}
});
});
</script>
</body>
</html>
建好擺資料的資料夾後,node server.js了一下
順利完成了