搭建koa基礎(chǔ)結(jié)構(gòu)
- 新建一個(gè)文件夾
- 執(zhí)行npm init -y
- 安裝koa koa-router
npm install koa koa-router --save
- 新建app.js引入:
const Koa = require('koa')
const app = new Koa()
const Router = require('koa-router')
const router = new Router()
// 路由寫在最下面
app.use(router.routes())
app.use(router.allowedMethods()) // 允許http請(qǐng)求的所有方法
app.listen(3000, (ctx) => {
console.log('服務(wù)開啟在三千端口')
})
- 開啟服務(wù):
執(zhí)行node app.js竞思,命令行打印'服務(wù)開啟在三千端口'表示開啟成功奕剃,因?yàn)槭亲詈?jiǎn)單的搭建唠叛,改了任何東西都要重新執(zhí)行 node app.js
編寫和引入路由
- 根目錄新建route文件夾骇吭,新建index.js
- 編寫index.js:
const Router = require('koa-router')
const router = new Router()
router.get('/', async (ctx, next) => {
ctx.body = ctx.request
})
module.exports = router
- app.js中引入,寫在app.use(router.routes())的上面:
....
const index = require('./route/index')
/**
這里可以寫成app.use('/', index.routes())
第一個(gè)參數(shù)代表這個(gè)文件路由的前綴,訪問時(shí)就得加上設(shè)置的前綴
*/
router.use(index.routes())
app.use(router.routes())
app.use(router.allowedMethods()) // 允許http請(qǐng)求的所有方法
...
-
此時(shí)訪問localhost:3000:
處理post請(qǐng)求參數(shù)
文件上傳請(qǐng)求肯定是post請(qǐng)求,koa中處理post請(qǐng)求參數(shù)需要安裝一個(gè)中間件
- 安裝koa-body
npm install koa-body --save
- app.js中引入和使用:
...
const koaBody = require('koa-body')
// 接收post參數(shù)解析概疆,寫在路由的前面
app.use(koaBody({
multipart: true
}))
// userouter
...
我們處理文件上傳需要在koaBody的配置設(shè)置multipart 為 true,這樣上傳的文件也就是formdata峰搪,會(huì)被koaBody處理在ctx.request.files中岔冀,其他普通的參數(shù)通過ctx.request.body就可以拿到:
拿文件:
const file = ctx.request.files['上傳文件的字段名']
普通參數(shù):
const data = ctx.request.body
編寫上傳接口與前端代碼
- 在route文件夾下新建一個(gè)upload.js,假設(shè)規(guī)定上傳的文件字段名叫file概耻,假設(shè)只上傳一個(gè)文件:
const Router = require('koa-router')
const router = new Router()
router.post('/upload', async (ctx, next) => {
const { name, path: filePath, size, type } = ctx.request.files.file
ctx.body = {
name, // 文件名稱
filePath, // 臨時(shí)路徑
size, // 文件大小
type // 文件類型
}
})
module.exports = router
上傳的文件會(huì)包含上面那個(gè)幾個(gè)字段使套,其中path為臨時(shí)路徑罐呼,把他們返回,下面會(huì)把接口請(qǐng)求結(jié)果貼出來童漩,看一下就知道各個(gè)字段的含義弄贿。
- app.js中引入路由與處理跨域
因?yàn)樵诒镜啬M,前端我會(huì)直接寫一個(gè)html文件矫膨,所以會(huì)出現(xiàn)跨域差凹,這里順便解決一下
npm install koa-cors --save
app中引入并使用:
// 放在最前面
const cors = require('koa-cors')
app.use(cors({
origin: '*'
}))
引入upload路由:
const upload = require('./route/upload')
router.use(upload.routes())
- 前端代碼:
<body>
<input type="file" name="file" id="file" value="" />
<button id="submit">上傳</button>
<script>
document.getElementById('submit').addEventListener('click', function() {
var file = document.getElementById('file').files[0]
if(!file) {
alert('請(qǐng)上傳文件')
return
}
console.log(file)
var formdata = new FormData()
formdata.append("file", file)
var xhr = new XMLHttpRequest()
xhr.open("post", "http://localhost:3000/upload")
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200) {
const result = JSON.parse(xhr.response)
console.log(result)
}
}
xhr.send(formdata)
})
</script>
</body>
這里用了原生的ajax,返回的response是個(gè)json字符串
- 發(fā)送請(qǐng)求以及返回?cái)?shù)據(jù)
當(dāng)我選擇一個(gè)文件并點(diǎn)擊上傳后:
可以看到侧馅,在koa接口返回的數(shù)據(jù)這里都能正常展示危尿,上面說到在router中,通過ctx.request.files.file拿到的path是臨時(shí)路徑馁痴,現(xiàn)在應(yīng)該明確了吧谊娇,可以看到這個(gè)路徑是存在我們電腦保存臨時(shí)文件的地方,我們直接訪問這個(gè)路徑就是我們剛上傳的圖片罗晕,也就是說前端上傳文件济欢,在我們處理之前,koa會(huì)把我們的文件放在一個(gè)臨時(shí)目錄上小渊,文件信息會(huì)放在ctx.request.files上法褥,這時(shí)候我們只要把文件轉(zhuǎn)移到我們想要的地方就可以。 - 移動(dòng)文件
上面說到要把文件從臨時(shí)目錄移動(dòng)到我們想存儲(chǔ)的地方酬屉,移動(dòng)文件可以用node原生的fs模塊半等,這里我用一個(gè)fs的拓展庫:fs-extra,操作起來比較方便呐萨,api也很簡(jiǎn)單杀饵。fs-extra文檔
安裝: npm install fs-extra --save
改一下我們的upload接口,upload.js:
const Router = require('koa-router')
const router = new Router()
const path = require('path')
const fse = require('fs-extra')
router.post('/upload', async (ctx, next) => {
const { name, path: filePath, size, type } = ctx.request.files.file
const dest = path.join(__dirname, '../upload', name) // 目標(biāo)目錄谬擦,沒有沒有這個(gè)文件夾會(huì)自動(dòng)創(chuàng)建
await fse.move(filePath, dest) // 移動(dòng)文件
ctx.body = {
name, // 文件名稱
filePath, // 臨時(shí)路徑
size, // 文件大小
type // 文件類型
}
})
module.exports = router
然后我們重新上傳一下文件
上傳成功后切距,在我們koa項(xiàng)目的文件夾中,會(huì)自動(dòng)多出來一個(gè)upload文件夾惨远,里面就有我們上傳的圖片:
然后我們復(fù)制返回的filepath蔚舀,也就是文件上傳后的臨時(shí)路徑:
可以看到存在我們電腦臨時(shí)目錄下的文件就被移動(dòng)走,相當(dāng)于刪除锨络。
koa處理靜態(tài)資源
其實(shí)上面已經(jīng)實(shí)現(xiàn)了圖片上傳并且保存到我們想要的位置赌躺,那怎么訪問呢,前端怎么展示呢羡儿,這就需要處理靜態(tài)資源了礼患。
- koa-static安裝與使用
npm install koa-static --save
在app.js中:
const koaStatic = require('koa-static')
// 填上我們存放圖片文件路徑
app.use(koaStatic(path.join(__dirname, './upload/')))
這時(shí)候我們就可以直接通過圖片的文件名訪問圖片了,我們上面上傳的一張圖片叫girl.jpg,這時(shí)候直接訪問:
- 返回url與前端展示
可以看到圖片可以直接展示了缅叠,所以我們這時(shí)候只需要把圖片的名稱返回給前端就可以悄泥,把接口修改一下,此時(shí)訪問圖片的url就是圖片的名稱肤粱,當(dāng)然看你們具體的邏輯弹囚,如果上面保存圖片保存在../upload/img/xxx.jpg,那么訪問圖片的url就變成/img/xxx.jpg
router.post('/upload', async (ctx, next) => {
const { name, path: filePath, size, type } = ctx.request.files.file
const dest = path.join(__dirname, '../upload', name) // 目標(biāo)目錄领曼,沒有沒有這個(gè)文件夾會(huì)自動(dòng)創(chuàng)建
await fse.move(filePath, dest) // 移動(dòng)文件
ctx.body = {
name, // 文件名稱
filePath, // 臨時(shí)路徑
size, // 文件大小
type, // 文件類型
url: name
}
})
前端加個(gè)img標(biāo)簽展示圖片:
<body>
<input type="file" name="file" id="file" value="" />
<button id="submit">上傳</button>
<img style="width:500px" src="" alt="">
<script>
document.getElementById('submit').addEventListener('click', function() {
var file = document.getElementById('file').files[0]
if(!file) {
alert('請(qǐng)上傳文件')
return
}
console.log(file)
var formdata = new FormData()
formdata.append("file", file)
var xhr = new XMLHttpRequest()
xhr.open("post", "http://localhost:3000/upload")
xhr.onreadystatechange = function() {
if(xhr.readyState === 4 && xhr.status === 200) {
const result = JSON.parse(xhr.response)
console.log(result)
document.querySelector('img').setAttribute('src', 'http://localhost:3000/' + result.url)
}
}
xhr.send(formdata)
})
</script>
</body>
前端上傳后:
添加參數(shù)
如果需要添加其他參數(shù)鸥鹉,就在formdata中再append其他參數(shù)
- 前端添加參數(shù)
...
var formdata = new FormData()
formdata.append("file", file)
// 傳其他參數(shù)
formdata.append("other", "test")
...
- 后端處理其他參數(shù):
router.post('/upload', async (ctx, next) => {
const { name, path: filePath, size, type } = ctx.request.files.file
const dest = path.join(__dirname, '../upload', name)
await fse.move(filePath, dest, { overwrite: true })
ctx.body = {
name, // 文件名稱
filePath, // 臨時(shí)路徑
size, // 文件大小
type, // 文件類型
url: name,
data: ctx.request.body // 其他參數(shù),會(huì)自動(dòng)過濾file
}
})
這時(shí)候把ctx.request.body返回給前端庶骄,看看是什么樣的:
可以看到 ctx.request.body 會(huì)自動(dòng)過濾掉上傳的文件參數(shù)毁渗,通過這個(gè)我們就可以拿到其他普通的參數(shù),這個(gè)邏輯和一些框架中的上傳組件是一樣的单刁。
到這里整個(gè)功能就實(shí)現(xiàn)了灸异,歡迎大家指教哦。