公司幾個項目都是三層架構模式即前臺,中臺(中間層),後臺。前臺微信端公衆號使用vue框架,後臺管理前端使用react,中臺(中間層)使用node,後臺使用java。這次說的是後臺關鍵上傳數據文件時遇到的一個bug,由於是三層架構,前臺表單會先提交到node中間層,而後再經過node中間層轉發到java後臺保存並讀取文件數據。 這次遇到了一個bug當表單提交到node中間層的時候node接口request能夠獲取獲得表單上傳的文件信息,就在node端建立http請求轉發到後臺的時候後臺報錯了:the request was rejected because no multipart boundary was found後臺收到的接口請求中得不到boundary信息,此時已肯定node建立的http請求中headers中Content-Type爲multipart/form-data,很顯然java後臺沒收到上傳文件信息,經過在頁面建立form表單使用後臺上傳接口地址發現後臺能夠上傳,這證實後臺接口沒問題,node中臺接口也能收到form表單上傳文件數據,那麼範圍進一步縮小問題就出如今node http請求轉發到後臺這步的問題了。既而後臺接口請求體中沒有boundary那麼問題就出如今建立請求的時候少給了東西后臺了,Google+百度了一下找到的解決方式在發現都不行,不能說徹底沒有用可是仍是找到了方向。後臺要的是表單數據,那node中臺轉發的時候就轉發一個表單數據。因而找到了form-data這個包及connect-multiparty中間件。 先插入一段代碼而後再分析;javascript
const fs = require('fs')
const path = require('path')
const FormData = require('form-data')
const express = require('express')
const fetch = require('node-fetch')
const router = express.Router()
const multipart = require('connect-multiparty');
var multipartMiddleware = multipart()
router.post('/uploadFile', multipartMiddleware, (req, res) => {
const { path: filePath, originalFilename } = req.files.file
const newPath = path.join(path.dirname(filePath), originalFilename) // 獲得newPath新地址用於建立讀取流
fs.rename(filePath, newPath, (err) => {
if (err) {
return;
} else {
const file = fs.createReadStream(newPath) //建立讀取流
const form = new FormData() // new formdata實例
form.append('file', file) // 把文件加入到formdata實例中
fetch('後臺接口上傳地址like:https://ip:端口/接口', {
method: "POST",
body: form,
headers: form.getHeaders() // 這步很是重要必定要把formdata的headers放在請求體headers中我發現網上不少例子講的都沒這個headers,沒有這個後臺仍是會報boundary的錯由於boundary是在request headers中
}).then(res => res.json()).then(data => {
res.send({data: data}) //將上傳結果返回給前端
})
}
})
});
複製代碼
這種方式沒有使用node http請求使用到了fetch,只是一種請求方式,換成axios其實也是同樣的,最主要的是發送請求的時候除了往formdata中append file文件信息外,headers必定要是formdata的headers否則後臺仍是接收不到request中的boundary。前端
const fs = require('fs')
const path = require('path')
const FormData = require('form-data')
const express = require('express')
var http = require('http');
const router = express.Router()
const multipart = require('connect-multiparty');
var multipartMiddleware = multipart()
router.post('/uploadFile', multipartMiddleware, (req, res) => {
const { path: filePath, originalFilename } = req.files.file
const newPath = path.join(path.dirname(filePath), originalFilename) // 獲得newPath新地址用於建立讀取流
fs.rename(filePath, newPath, (err) => {
if (err) {
return;
} else {
const file = fs.createReadStream(newPath) //建立讀取流
const form = new FormData() // new formdata實例
form.append('file', file) // 把文件加入到formdata實例中
var request = http.request({
method: 'post',
host: 'http://ip:port',
path: '/xxxx', //上傳接口
headers: form.getHeaders() //formdata的headers
});
form.pipe(request);
request.on('response', (response) => {
res.send({data: response})
});
}
})
})
複製代碼
這種方式使用的是node中http方式,相關注意事項其實跟node-fetch差很少只是發送的差異而已。vue
今天週末有時間總結一下,最後若是有不對的地方但願你們指正一塊兒學習,謝謝!java