欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

node 文件上傳接口的轉(zhuǎn)發(fā)的實(shí)現(xiàn)

 更新時(shí)間:2019年09月23日 12:05:30   作者:三石流浪記  
這篇文章主要介紹了node 文件上傳接口的轉(zhuǎn)發(fā)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

近期的項(xiàng)目里使用了這樣一個(gè)項(xiàng)目架構(gòu): 前端 -> nodejs -> java

  • 前端負(fù)責(zé)實(shí)現(xiàn)業(yè)務(wù)邏輯的展示和交互
  • nodejs 包括維護(hù)某些數(shù)據(jù)和接口轉(zhuǎn)發(fā)
  • java 負(fù)責(zé)維護(hù)剩下的數(shù)據(jù)

在 nodejs 的接口轉(zhuǎn)發(fā)中攔截一部分接口,再對(duì)請(qǐng)求的方法進(jìn)行區(qū)分,請(qǐng)求后臺(tái)數(shù)據(jù)后,再進(jìn)行返回。現(xiàn)有的接口中基本只用到了 get 和 post 兩種,但是在文件上傳的時(shí)候遇到了問(wèn)題。

node 層使用 eggjs ,一般的 post 的請(qǐng)求直接在 ctx.body 就能拿到請(qǐng)求的參數(shù),但是 /upload 的接口就不行,拿到的 body 是 {} ,下面我們來(lái)逐步分析。

js 中的文件

 web 中的 Blob 、File 和 Formdate

一個(gè) Blob ( Binary Large Object ) 對(duì)象表示一個(gè)不可變的, 原始數(shù)據(jù)的類似文件對(duì)象。Blob表示的數(shù)據(jù)不一定是一個(gè)JavaScript原生格式。 File 接口基于Blob,繼承 Blob 功能并將其擴(kuò)展為支持用戶系統(tǒng)上的文件。

前端上傳文件的方式無(wú)非就是使用:1、表單自動(dòng)上傳;2、使用 ajax 上傳。我們可以使用以下代碼創(chuàng)建一個(gè) Form,并打印出 file

<form method="POST" id="uploadForm" enctype="multipart/form-data">
 <input type="file" id="file" name="file" />
</form>

<button id="submit">submit</button>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>

<script>
 $("#submit").click(function() {
  console.log($("#file")[0].files[0])
 });
</script>

從 F12 中可以看出 File 原型鏈上是 Blob。

簡(jiǎn)單地說(shuō) Blob 可以理解為 Web 中的二進(jìn)制文件。 而 File 是基于 Blob 實(shí)現(xiàn)的一個(gè)類,新增了關(guān)于文件有關(guān)的一些信息。

FormData對(duì)象的作用就類似于 Jq 的 serialize() 方法,不過(guò) FormData 是瀏覽器原生的,且支持二進(jìn)制文件。 ajax 通過(guò) FormData 這個(gè)對(duì)象發(fā)送表單請(qǐng)求,無(wú)論是原生的 XMLHttpRequest 、jq 的 ajax 方法、 axios 都是在 data 里直接指定上傳 formData 類型的數(shù)據(jù),fetch api 是在 body 里上傳。

forData 數(shù)據(jù)有兩種方式生成,如下 formData 和 formData2 的區(qū)別,而 formData2 可以通過(guò)傳入一個(gè) element 的方式進(jìn)行初始化,初始化之后依然可以調(diào)用 formData 的 append 方法。

<!DOCTYPE html>
<html>
 <form method="POST" id="uploadForm" name="uploadFormName" enctype="multipart/form-data">
 <input type="file" id="fileImag" name="configFile" />
 </form>
 <div id="show"></div>

 <button id="submit">submit</button>
 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
</html>

<script>
 $("#submit").click(function() {
 const file = $("#fileImag")[0].files[0];
 
 const formData = new FormData();
 
 formData.append("fileImag", file);
 console.log(formData.getAll("fileImag"));

 const formData2 = new FormData(document.querySelector("#uploadForm"));
 // const formData2 = new FormData(document.forms.namedItem("uploadFormName"););
 console.log(formData2.get("configFile"));
 
 });
</script>

console.log() 無(wú)法直接打印出 formData 的數(shù)據(jù),可以使用 get(key) 或者 getAll(key)

  • 如果是使用 new FormData(element) 的創(chuàng)建方式,上面 key 為 <input /> 上的 name 字段。
  • 如果是使用 append 添加的數(shù)據(jù),get/getAll 時(shí) key 為 append 所指定的 key。

node 中的 Buffer 、 Stream 、fs

Buffer 和 Stream 是 node 為了讓 js 在后端擁有處理二進(jìn)制文件而出現(xiàn)的數(shù)據(jù)結(jié)構(gòu)。

通過(guò)名字可以看出 buffer 是緩存的意思。存儲(chǔ)在內(nèi)存當(dāng)中,所以大小有限,buffer 是 C++ 層面分配的,所得內(nèi)存不在 V8 內(nèi)。

stream 可以用水流形容數(shù)據(jù)的流動(dòng),在文件 I/O、網(wǎng)絡(luò) I/O中數(shù)據(jù)的傳輸都可以稱之為流。

通過(guò)兩個(gè) fs 的 api 看出,readFile 不指定字符編碼默認(rèn)返回 buffer 類型,而 createReadStream 將文件轉(zhuǎn)化為一個(gè) stream , nodejs 中的 stream 通過(guò) data 事件能夠一點(diǎn)一點(diǎn)地拿到文件內(nèi)容,直到 end 事件響應(yīng)為止。

const fs = require("fs");

fs.readFile("./package.json", function(err, buffer) {
 if (err) throw err;
 console.log("buffer", buffer);
});

function readLines(input, func) {
 var remaining = "";

 input.on("data", function(data) {
 remaining += data;
 var index = remaining.indexOf("\n");
 var last = 0;
 while (index > -1) {
  var line = remaining.substring(last, index);
  last = index + 1;
  func(line);
  index = remaining.indexOf("\n", last);
 }

 remaining = remaining.substring(last);
 });

 input.on("end", function() {
 if (remaining.length > 0) {
  func(remaining);
 }
 });
}

function func(data) {
 console.log("Line: " + data);
}

var input = fs.createReadStream("./package.json");
input.setEncoding("binary");

readLines(input, func);

fs.readFile() 函數(shù)會(huì)緩沖整個(gè)文件。 為了最小化內(nèi)存成本,盡可能通過(guò) fs.createReadStream() 進(jìn)行流式傳輸。

使用 nodejs 創(chuàng)建 uoload api

http 協(xié)議中的文件上傳

在 http 的請(qǐng)求頭中 Content-type 是 multipart/form-data 時(shí),請(qǐng)求的內(nèi)容如下:

POST / HTTP/1.1
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryoMwe4OxVN0Iuf1S4
Origin: http://localhost:3000
Referer: http://localhost:3000/upload
Sec-Fetch-Mode: navigate
Sec-Fetch-User: ?1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/76.0.3809.132 Safari/537.36

------WebKitFormBoundaryoqBx9oYBhx4SF1YQ
Content-Disposition: form-data; name="upload"

http://localhost:3000
------WebKitFormBoundaryoMwe4OxVN0Iuf1S4
Content-Disposition: form-data; name="upload"; filename="IMG_9429.JPG"
Content-Type: image/jpeg

����JFIF��C // 文件的二進(jìn)制數(shù)據(jù)
……
--------WebKitFormBoundaryoMwe4OxVN0Iuf1S4--

根據(jù) WebKitFormBoundaryoMwe4OxVN0Iuf1S4 可以分割出文件的二進(jìn)制內(nèi)容

原生 node

使用原生的 node 寫(xiě)一個(gè)文件上傳的 demo

const http = require("http");
const fs = require("fs");
const util = require("util");
const querystring = require("querystring");

//用http模塊創(chuàng)建一個(gè)http服務(wù)端
http
 .createServer(function(req, res) {
 if (req.url == "/upload" && req.method.toLowerCase() === "get") {
 
  //顯示一個(gè)用于文件上傳的form
  res.writeHead(200, { "content-type": "text/html" });
  res.end(
  '<form action="/upload" enctype="multipart/form-data" method="post">' +
   '<input type="file" name="upload" multiple="multiple" />' +
   '<input type="submit" value="Upload" />' +
   "</form>"
  );
 } else if (req.url == "/upload" && req.method.toLowerCase() === "post") {
  if (req.headers["content-type"].indexOf("multipart/form-data") !== -1)
  parseFile(req, res);
 } else {
  res.end("pelease upload img");
 }
 })
 .listen(3000);

function parseFile(req, res) {
 req.setEncoding("binary");
 let body = ""; // 文件數(shù)據(jù)
 let fileName = ""; // 文件名
 
 // 邊界字符串 ----WebKitFormBoundaryoMwe4OxVN0Iuf1S4
 const boundary = req.headers["content-type"]
 .split("; ")[1]
 .replace("boundary=", "");
 
 
 req.on("data", function(chunk) {
 body += chunk;
 });

 req.on("end", function() {
 const file = querystring.parse(body, "\r\n", ":");

 // 只處理圖片文件;
 if (file["Content-Type"].indexOf("image") !== -1) {
  //獲取文件名
  var fileInfo = file["Content-Disposition"].split("; ");
  for (value in fileInfo) {
  if (fileInfo[value].indexOf("filename=") != -1) {
   fileName = fileInfo[value].substring(10, fileInfo[value].length - 1);

   if (fileName.indexOf("\\") != -1) {
   fileName = fileName.substring(fileName.lastIndexOf("\\") + 1);
   }
   console.log("文件名: " + fileName);
  }
  }

  // 獲取圖片類型(如:image/gif 或 image/png))
  const entireData = body.toString();
  const contentTypeRegex = /Content-Type: image\/.*/;

  contentType = file["Content-Type"].substring(1);

  //獲取文件二進(jìn)制數(shù)據(jù)開(kāi)始位置,即contentType的結(jié)尾
  const upperBoundary = entireData.indexOf(contentType) + contentType.length;
  const shorterData = entireData.substring(upperBoundary);

  // 替換開(kāi)始位置的空格
  const binaryDataAlmost = shorterData
  .replace(/^\s\s*/, "")
  .replace(/\s\s*$/, "");

  // 去除數(shù)據(jù)末尾的額外數(shù)據(jù),即: "--"+ boundary + "--"
  const binaryData = binaryDataAlmost.substring(
  0,
  binaryDataAlmost.indexOf("--" + boundary + "--")
  );

  // console.log("binaryData", binaryData);
  const bufferData = new Buffer.from(binaryData, "binary");
  console.log("bufferData", bufferData);

  // fs.writeFile(fileName, binaryData, "binary", function(err) {
  // res.end("sucess");
  // });
  fs.writeFile(fileName, bufferData, function(err) {
  res.end("sucess");
  });
 } else {
  res.end("reupload");
 }
 });
}

通過(guò) req.setEncoding("binary"); 拿到圖片的二進(jìn)制數(shù)據(jù)??梢酝ㄟ^(guò)以下兩種方式處理二進(jìn)制數(shù)據(jù),寫(xiě)入文件。

fs.writeFile(fileName, binaryData, "binary", function(err) {
 res.end("sucess");
});
fs.writeFile(fileName, bufferData, function(err) {
 res.end("sucess");
});

koa

在 koa 中使用 koa-body 可以通過(guò) ctx.request.files 拿到上傳的 file 對(duì)象。下面是例子。

'use strict';

const Koa  = require('koa');
const app  = new Koa();
const router = require('koa-router')();
const koaBody = require('../index')({multipart:true});

router.post('/users', koaBody,
 (ctx) => {
 console.log(ctx.request.body);
 // => POST body
 ctx.body = JSON.stringify(ctx.request.body, null, 2);
 }
);

router.get('/', (ctx) => {
 ctx.set('Content-Type', 'text/html');
 ctx.body = `
<!doctype html>
<html>
 <body>
 <form action="/" enctype="multipart/form-data" method="post">
 <input type="text" name="username" placeholder="username"><br>
 <input type="text" name="title" placeholder="tile of film"><br>
 <input type="file" name="uploads" multiple="multiple"><br>
 <button type="submit">Upload</button>
 </body>
</html>`;
});

router.post('/', koaBody,
 (ctx) => {
 console.log('fields: ', ctx.request.body);
 // => {username: ""} - if empty

 console.log('files: ', ctx.request.files);
 /* => {uploads: [
   {
    "size": 748831,
    "path": "/tmp/f7777b4269bf6e64518f96248537c0ab.png",
    "name": "some-image.png",
    "type": "image/png",
    "mtime": "2014-06-17T11:08:52.816Z"
   },
   {
    "size": 379749,
    "path": "/tmp/83b8cf0524529482d2f8b5d0852f49bf.jpeg",
    "name": "nodejs_rulz.jpeg",
    "type": "image/jpeg",
    "mtime": "2014-06-17T11:08:52.830Z"
   }
   ]}
 */
 ctx.body = JSON.stringify(ctx.request.body, null, 2);
 }
)

app.use(router.routes());

const port = process.env.PORT || 3333;
app.listen(port);
console.log('Koa server with `koa-body` parser start listening to port %s', port);
console.log('curl -i http://localhost:%s/users -d "user=admin"', port);
console.log('curl -i http://localhost:%s/ -F "source=@/path/to/file.png"', port);

我們來(lái)看一下 koa-body 的實(shí)現(xiàn)

const forms = require('formidable');

function requestbody(opts) {
 opts = opts || {};
 ...
 opts.multipart = 'multipart' in opts ? opts.multipart : false;
 opts.formidable = 'formidable' in opts ? opts.formidable : {};
 ...


 // @todo: next major version, opts.strict support should be removed
 if (opts.strict && opts.parsedMethods) {
 throw new Error('Cannot use strict and parsedMethods options at the same time.')
 }

 if ('strict' in opts) {
 console.warn('DEPRECATED: opts.strict has been deprecated in favor of opts.parsedMethods.')
 if (opts.strict) {
  opts.parsedMethods = ['POST', 'PUT', 'PATCH']
 } else {
  opts.parsedMethods = ['POST', 'PUT', 'PATCH', 'GET', 'HEAD', 'DELETE']
 }
 }

 opts.parsedMethods = 'parsedMethods' in opts ? opts.parsedMethods : ['POST', 'PUT', 'PATCH']
 opts.parsedMethods = opts.parsedMethods.map(function (method) { return method.toUpperCase() })

 return function (ctx, next) {
 var bodyPromise;
 // only parse the body on specifically chosen methods
 if (opts.parsedMethods.includes(ctx.method.toUpperCase())) {
  try {
  if (opts.json && ctx.is(jsonTypes)) {
   bodyPromise = buddy.json(ctx, {
   encoding: opts.encoding,
   limit: opts.jsonLimit,
   strict: opts.jsonStrict,
   returnRawBody: opts.includeUnparsed
   });
  } else if (opts.multipart && ctx.is('multipart')) {
   bodyPromise = formy(ctx, opts.formidable);
  }
  } catch (parsingError) {
  if (typeof opts.onError === 'function') {
   opts.onError(parsingError, ctx);
  } else {
   throw parsingError;
  }
  }
 }

 bodyPromise = bodyPromise || Promise.resolve({});
 

/**
 * Check if multipart handling is enabled and that this is a multipart request
 *
 * @param {Object} ctx
 * @param {Object} opts
 * @return {Boolean} true if request is multipart and being treated as so
 * @api private
 */
function isMultiPart(ctx, opts) {
 return opts.multipart && ctx.is('multipart');
}

/**
 * Donable formidable
 *
 * @param {Stream} ctx
 * @param {Object} opts
 * @return {Promise}
 * @api private
 */
function formy(ctx, opts) {
 return new Promise(function (resolve, reject) {
 var fields = {};
 var files = {};
 var form = new forms.IncomingForm(opts);
 form.on('end', function () {
  return resolve({
  fields: fields,
  files: files
  });
 }).on('error', function (err) {
  return reject(err);
 }).on('field', function (field, value) {
  if (fields[field]) {
  if (Array.isArray(fields[field])) {
   fields[field].push(value);
  } else {
   fields[field] = [fields[field], value];
  }
  } else {
  fields[field] = value;
  }
 }).on('file', function (field, file) {
  if (files[field]) {
  if (Array.isArray(files[field])) {
   files[field].push(file);
  } else {
   files[field] = [files[field], file];
  }
  } else {
  files[field] = file;
  }
 });
 if (opts.onFileBegin) {
  form.on('fileBegin', opts.onFileBegin);
 }
 form.parse(ctx.req);
 });
}

代碼中刪除了影響有關(guān)文件上傳的相關(guān)邏輯

  • 首先 multipart 為 true 是開(kāi)啟文件上傳的關(guān)鍵。
  • 然后 formy 函數(shù)處理了 http 解析和保存的一系列過(guò)程,最終將 files 拋出進(jìn)行統(tǒng)一處理。代碼中依賴了 formidable 這個(gè)庫(kù),我們其實(shí)也可以直接使用這個(gè)庫(kù)對(duì)文件進(jìn)行處理。(上面的原生 node upload 只是簡(jiǎn)單地處理了一下)
  • opts.formidable 是 formidable 的 config 可以設(shè)置文件大小,保存的文件路徑等等。

 eggjs

使用 eggjs 進(jìn)行文件上傳需要現(xiàn)在配置文件中開(kāi)啟

 config.multipart = { mode: "file", fileSize: "600mb" };

然后通過(guò) ctx.request.files[0] 就能取到文件信息。

文件上傳接口的轉(zhuǎn)發(fā)

一千個(gè)觀眾眼中有一千個(gè)哈姆雷特,通過(guò)以上知識(shí)點(diǎn)的梳理,我相信你也有了自己得想法。在這里說(shuō)一下我是怎么處理的。 在 egg 中我使用了 request-promise 去做接口轉(zhuǎn)發(fā),通過(guò)查看 api 和 ctx.request.files[0] 拿到的信息,我做了以下處理。

 if (method === "POST") {
  options.body = request.body;
  options.json = true;
  if (url === uploadeUrl) {
  delete options.body;

  options.formData = {
   // Like <input type="text" name="name">
   name: "file",
   // Like <input type="file" name="file">
   file: {
   value: fs.createReadStream(ctx.request.files[0].filepath),
   options: {
    filename: ctx.request.files[0].filename,
    contentType: ctx.get("content-type")
   }
   }
  };
  }
 } else {
  options.qs = query;
 }

總結(jié)

  • http 中的文件上傳第一步就是設(shè)置 Content-type 為 multipart/form-data 的 header。
  • 區(qū)分好 web 端 js 和 node 端處理文件的方式有所不同。
  • 有些 npm 模塊的 readme 并不是很清晰,可以直接下源碼去看 example ,或者直接讀源碼,就比如上文中沒(méi)有提到的 koa-body 中 formidable 的用法并未在他的 reademe 中寫(xiě)出,直接看源碼會(huì)發(fā)現(xiàn)更多用法。
  • 文中的知識(shí)點(diǎn)很多知識(shí)稍微提及,可以進(jìn)一步深入了解與他相關(guān)的知識(shí)。比如 web 的 FileReader 等等。
  • 最后如果文中有任何錯(cuò)誤請(qǐng)及時(shí)指出,有任何問(wèn)題可以討論。

參考

http://www.dbjr.com.cn/article/170637.htm

https://www.npmjs.com/package/formidable

https://github.com/dlau/koa-body

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Node.js斷點(diǎn)續(xù)傳的實(shí)現(xiàn)

    Node.js斷點(diǎn)續(xù)傳的實(shí)現(xiàn)

    最近做了個(gè)項(xiàng)目,應(yīng)項(xiàng)目需求,需要傳圖片、Excel等,幾M的大小可以很快就上傳到服務(wù)器,但是大的就需要斷點(diǎn)上傳,本文就介紹一下,感興趣的可以了解一下
    2021-05-05
  • 淺談NodeJS中require路徑問(wèn)題

    淺談NodeJS中require路徑問(wèn)題

    學(xué)習(xí)Nodejs也是出于對(duì)這個(gè)新產(chǎn)物的好奇,而且有兩個(gè)重要項(xiàng)目也需要他的支持,所以要好好學(xué)學(xué)這個(gè)新語(yǔ)種。在nodejs中,模塊大概可以分為核心模塊和文件模塊。核心模塊是被編譯成二進(jìn)制代碼,引用的時(shí)候只需require表示符即可
    2015-05-05
  • koa中間件核心(koa-compose)源碼解讀分析

    koa中間件核心(koa-compose)源碼解讀分析

    這篇文章主要介紹了koa中間件核心(koa-compose)源碼解讀分析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • nodejs通過(guò)phantomjs實(shí)現(xiàn)下載網(wǎng)頁(yè)

    nodejs通過(guò)phantomjs實(shí)現(xiàn)下載網(wǎng)頁(yè)

    這篇文章主要介紹了nodejs通過(guò)phantomjs實(shí)現(xiàn)下載網(wǎng)頁(yè)的方法,有需要的小伙伴可以參考下。
    2015-05-05
  • Node.js自定義對(duì)象事件的監(jiān)聽(tīng)與發(fā)射

    Node.js自定義對(duì)象事件的監(jiān)聽(tīng)與發(fā)射

    這篇文章介紹了Node.js自定義對(duì)象事件監(jiān)聽(tīng)與發(fā)射的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • 如何利用nodejs自動(dòng)定時(shí)發(fā)送郵件提醒(超實(shí)用)

    如何利用nodejs自動(dòng)定時(shí)發(fā)送郵件提醒(超實(shí)用)

    這篇文章主要給大家介紹了關(guān)于如何利用nodejs實(shí)現(xiàn)自動(dòng)定時(shí)發(fā)送郵件提醒的相關(guān)資料,這個(gè)功能非常實(shí)用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Node.js處理多個(gè)請(qǐng)求的技巧和方法

    Node.js處理多個(gè)請(qǐng)求的技巧和方法

    Node.js在處理多個(gè)請(qǐng)求方面具有優(yōu)勢(shì),它利用事件驅(qū)動(dòng)和非阻塞式I/O的特性,能夠高效地處理并發(fā)請(qǐng)求,提供快速響應(yīng)和良好的可擴(kuò)展性,這篇文章主要介紹了Node.js如何處理多個(gè)請(qǐng)求,需要的朋友可以參考下
    2023-11-11
  • nodejs導(dǎo)出excel的方法

    nodejs導(dǎo)出excel的方法

    這篇文章主要介紹了nodejs導(dǎo)出excel的方法,實(shí)例分析了nodejs導(dǎo)出excel的詳細(xì)步驟與相關(guān)技巧,需要的朋友可以參考下
    2015-06-06
  • socket.io學(xué)習(xí)教程之基本應(yīng)用(二)

    socket.io學(xué)習(xí)教程之基本應(yīng)用(二)

    socket.io提供了基于事件的實(shí)時(shí)雙向通訊,下面這篇文章主要給大家介紹了socket.io基本應(yīng)用的相關(guān)資料,對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。
    2017-04-04
  • node跨域轉(zhuǎn)發(fā) express+http-proxy-middleware的使用

    node跨域轉(zhuǎn)發(fā) express+http-proxy-middleware的使用

    這篇文章主要介紹了node跨域轉(zhuǎn)發(fā) express+http-proxy-middleware的使用,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-05-05

最新評(píng)論