Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 久久久免费观看视频,免费在线精品视频,在线播放一区二区三区

          整合營銷服務(wù)商

          電腦端+手機端+微信端=數(shù)據(jù)同步管理

          免費咨詢熱線:

          node.js 上傳文件

          node.js 上傳文件

          工作中碰到了這樣的需求,需要用nodejs 來上傳文件,之前也只是知道怎么通過瀏覽器來上傳文件, 用nodejs的話, 相當(dāng)于模擬瀏覽器的行為。 google 了一番之后, 明白了瀏覽器無非就是利用http協(xié)議來給服務(wù)器傳輸數(shù)據(jù), 具體協(xié)議就是《RFC 1867 - Form-based File Upload in HTML》, 在瀏覽器上通過form 表單來上傳文件就是通過這個協(xié)議,我們可以先看看瀏覽器給服務(wù)端發(fā)送了什么數(shù)據(jù), 就可以依葫蘆畫瓢的把上傳功能實現(xiàn)出來。說起form 表單上傳文件的話, 大家應(yīng)該很熟悉:

          <form action="http://www.qq.com/" method="post">
              <input type="text" name="text1" /><br />
              <input type="text" name="text2" /><br />
              <input type="submit" />
          </form>

          提交時, 用fiddler 抓包可以看到向服務(wù)端發(fā)出這樣的數(shù)據(jù):

          POST http://www.qq.com/ HTTP/1.1
          Host: www.qq.com
          Content-Length: 23
          Content-Type: application/x-www-form-urlencoded; charset=UTF-8
          
          text1=hello&text2=world

          值得注意的是Content-Type默認(rèn)為application/x-www-form-urlencoded,所以消息會經(jīng)過URL編碼。比如你好會編碼為 %E4%BD%A0%E5%A5%BD。

          接下來我們看一下通過form 表單是怎么上傳的。大家應(yīng)該也不陌生:

          <form action="http://www.qq.com"  method="post" enctype="multipart/form-data">
              <input type="file" name="myfile" />
              <input type="submit" value="submit" />
          </form>

          然后新建一個只有hello world字樣的upload.txt文本文件上傳上去,我們再吃用fiddler 來抓下包, 可以發(fā)現(xiàn)發(fā)送過去的數(shù)據(jù)稍微復(fù)雜了一些(已經(jīng)去掉了很多的其它沒關(guān)系的請求行,比如緩存控制和cookie之類的):

          POST http://www.qq.com/ HTTP/1.1
          Host: www.qq.com
          Content-Length: 199
          Content-Type: multipart/form-data; boundary=----WebKitFormBoundarywr3X7sXBYQQ4ZF5G
          
          ------WebKitFormBoundarywr3X7sXBYQQ4ZF5G
          Content-Disposition: form-data; name="myfile"; filename="upload.txt"
          Content-Type: text/plain
          
          hello world
          
          ------WebKitFormBoundarywr3X7sXBYQQ4ZF5G--

          根據(jù)RFC 1867的定義,我們需要生成一段邊界數(shù)據(jù),這個數(shù)據(jù)不能在內(nèi)容的其它地方出現(xiàn),這個可以自己定義, 在每個瀏覽器的生成算法可能都不一樣, 上面的boundary就是分隔數(shù)據(jù),生成了分隔數(shù)據(jù)之后, 就可以把分隔數(shù)據(jù)放在頭部的Content-Type里面?zhèn)魉徒o服務(wù)端, 也就是上文的 Content-Type: multipart/form-data; boundary=----WebKitFormBoundarywr3X7sXBYQQ4ZF5G, 另外,上傳的內(nèi)容,需要用分隔數(shù)據(jù)來分隔成若干個段,然后每段數(shù)據(jù)里面都有文件的文件名,還有上傳時候的name,服務(wù)端就是用這個name來接收文件,還有文件的類型Content-Type,在這個例子里是 text/plain,如果上傳的是png圖片就是image/png。文件類型的一個空行后就是所上傳的文件的內(nèi)容,在這個例子里也是為了容易理解所以上傳的是文本文件所以內(nèi)容直接就能夠顯示出來,如果上傳的是圖片文件, 因為是二進制文件,fiddler 就顯示的是亂碼。 文件的內(nèi)容結(jié)束之后就是一個空行再加上邊界數(shù)據(jù)。

          了解了發(fā)送格式的細(xì)節(jié)之后, 下一步就是使用nodejs來編程實現(xiàn),簡單來講, 就是按照格式把數(shù)據(jù)發(fā)送給服務(wù)端就行了。

          const http=require('http');
          const fs=require('fs');
          
          //post地址為本地服務(wù)的一個php,用于測試上傳是否成功
          var options={
              hostname: 'localhost',
              port: 80,
              path: '/get.php',
              method: 'POST'
          }
          
          //生成分隔數(shù)據(jù)
          var boundaryKey='----WebKitFormBoundaryjLVkbqXtIi0YGpaB'; 
          
          //讀取需要上傳的文件內(nèi)容
          fs.readFile('./upload.txt', function (err, data) {
              //拼裝分隔數(shù)據(jù)段
              var payload='--' + boundaryKey + '\r\n' + 'Content-Disposition:form-data; name="myfile"; filename="upload.txt"\r\n' + 'Content-Type:text/plain\r\n\r\n';
              payload +=data;
              payload +='\r\n--' + boundaryKey + '--';
              
              //發(fā)送請求
              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.error("error:"+e);
              });
              //把boundary、要發(fā)送的數(shù)據(jù)大小以及數(shù)據(jù)本身寫進請求
              req.setHeader('Content-Type', 'multipart/form-data; boundary='+boundaryKey+'');
              req.setHeader('Content-Length', Buffer.byteLength(payload, 'utf8'));
              req.write(payload);
              req.end;
          });

          本文重點在于了解協(xié)議并且用代碼實現(xiàn)出來, 代碼組織上面還有很多優(yōu)化的地方。

          最后在本地apache,簡單寫一個php來保存上傳的文件來用作測試:

          <?php
          $filePath='./upload.txt';
          move_uploaded_file($_FILES['myfile']['tmp_name'] , $filePath);
          echo "ok";
          ?>

          另外,根據(jù)RFC 1867 還可以實現(xiàn)一次上傳多個文件的功能, 這個在這里就不詳述, 需要的話可以詳細(xì)參考RFC 1867來實現(xiàn)。

          標(biāo):

          上傳文件、文件夾

          給你三秒鐘,思考下可能用到哪些知識點

          前期準(zhǔn)備

          1.1 整體流程

          1. index.js模塊: 程序入口, 有服務(wù)器(server.js)和路由(route.js)和處理(handler.js)模塊組成;

          2. server.js模塊: 專門處理不同路由, 并做相應(yīng)的處理;

          3. route.js模塊: 請求的地址, 處理方法, 響應(yīng), 請求;

          4. handler.js模塊: 封裝不同的方法,交由路由route.js模塊來選擇調(diào)用;

          5. HTML文件: 存在HTML文件; 6. package.json模塊: CommonJS規(guī)定的規(guī)范;

          我想這個不同于理論的實踐,會慢慢為接下來打下堅實的基礎(chǔ)的。

          1.2 模塊包

          formidable是一個用于處理文件、圖片、視頻等數(shù)據(jù)上傳的模塊,支持GB級上傳數(shù)據(jù)處理,支持多種客戶端數(shù)據(jù)提交。有極高的測試覆蓋率,非常適合在生產(chǎn)環(huán)境中使用。

          npm配置安裝

          npm install formidable@latest

          util是一個Node.js核心模塊,util模塊設(shè)計的主要目的是為了滿足Node內(nèi)部API的需求。其中包括:格式化字符串、對象的序列化、實現(xiàn)對象繼承等常用方法。要使用util模塊中的方法,只需require('util')引入即可。

          1.3 package.json文件

          package.json:定義了這個項目所需要的各種模塊,以及項目的配置信息(比如名稱、版本、許可證等元數(shù)據(jù))。npm install命令根據(jù)這個配置文件,自動下載所需的模塊.

          1. scripts指定了運行腳本命令的npm命令行縮寫,比如start指定了運行npm run start時,所要執(zhí)行的命令。

          2. dependencies字段指定了項目運行所依賴的模塊;

          3. devDependencies指定項目開發(fā)所需要的模塊。

          指定版本:比如1.2.2,遵循“大版本.次要版本.小版本”的格式規(guī)定,安裝時只安裝指定版本。

          波浪號(tilde)+指定版本:比如~1.2.2,表示安裝1.2.x的最新版本(不低于1.2.2),但是不安裝1.3.x,也就是說安裝時不改變大版本號和次要版本號。

          插入號(caret)+指定版本:比如?1.2.2,表示安裝1.x.x的最新版本(不低于1.2.2),但是不安裝2.x.x,也就是說安裝時不改變大版本號。

          需要注意的是,如果大版本號為0,則插入號的行為與波浪號相同,這是因為此時處于開發(fā)階段,即使是次要版本號變動,也可能帶來程序的不兼容。 latest:安裝最新版本。

          例子如下:

          {

          "name": "upload",

          "version": "1.0.1",

          "description": "文件上傳下載",

          "main": "index.js",

          "scripts": {

          "start": "node index.js"

          },

          "author": "hhw",

          "license": "ISC"

          //依賴模塊

          "dependencies": {

          "formidable":"formidable@1.0.17",

          },

          }

          第二部分 代碼實現(xiàn)部分

          2.1 服務(wù)器server.js代碼實現(xiàn)

          //引入http utl 模塊

          var http=require('http');

          var url=require('url');

          //程序入口, 選擇路由, 并做相應(yīng)的處理

          function start(route, handler){

          //選擇路由

          function onRequest(request, response) {

          //url.parse(): 輸入 URL 字符串,返回一個對象。

          //對象中 pathname 所代表的路徑

          var pathname=url.parse(request.url).pathname;

          route(pathname, handler, response, request);

          }

          //服務(wù)器對不同的路由做出不同的響應(yīng)

          http.createServer(onRequest).listen(3000);

          }

          //導(dǎo)出接口

          exports.start=start;

          2.2 路由選擇代碼

          //具體處理路由的功能模塊

          //請求的地址, 處理方法<upload download...>, 響應(yīng), 請求

          function route(pathname, handler, response, request){

          //如果請求的方法是存在的函數(shù)就返回交給服務(wù)器處理

          if (typeof handler[pathname]==='function'){

          return handler[pathname](request, response);

          } else{

          //否則返回404

          response.writeHead(404, {'Content-Type': 'text/html'});

          response.write('404 Not Found!');

          response.end();

          }

          }

          exports.route=route;

          2.3 具體處理不同需求的代碼實現(xiàn)

          node-formidable

          //解析字符串, fs模塊, 格式化模塊

          var fs=require('fs'),

          formidable=require('formidable'),

          util=require('util'),

          http=require('http');

          const path=require('path');

          //程序入口展示HTML文件

          function home(request, response){

          //加載本地頁面HTML

          fs.readFile('./index.html', function(err, data) {

          response.writeHead(200, {'Content-Type': 'text/html'});

          response.write(data);

          response.end();

          });

          }

          //formidable是一個用于處理文件、圖片、視頻等數(shù)據(jù)上傳的模塊,支持GB級上傳數(shù)據(jù)處理,支持多種客戶端數(shù)據(jù)提交。有極高的測試覆蓋率,非常適合在生產(chǎn)環(huán)境中使用。

          function uploads(request, response) {

          //form表單

          var form=new formidable.IncomingForm();

          //保留后綴

          form.keepExtensions=true;

          form.encoding='utf-8';

          //上傳的數(shù)據(jù)保存的路徑

          form.uploadDir='./';

          //該方法會轉(zhuǎn)換請求中所包含的表單數(shù)據(jù),callback會包含所有字段域和文件信息

          // fields 是普通表單數(shù)據(jù)

          // files 是文件數(shù)據(jù)

          form.parse(request, function(err, fields, files) {

          response.writeHead(200, {'Content-type': 'text/plain'});

          //上傳文件的名稱

          var filename=files.upload.name;

          var path=files.upload.path;

          //更改名稱

          fs.rename(path, form.uploadDir + filename);

          //響應(yīng) 格式化打印

          response.end(util.inspect(form));

          });

          }

          function show (response, request) {

          console.log('show module');

          fs.readFile ('/tmp/test.png ', 'binary', function (error, file) {

          if (error) {

          response.writeHead(200, {'Content-Type': 'text/html'});

          response.write(error);

          response.end();

          } else {

          response.writeHead(200, {'Content-Type': 'image/png'});

          response.write(file, 'binary');

          response.end();

          }

          });

          }

          function downloads(requset, response){

          //node官網(wǎng)圖標(biāo)

          var URL="http://nodejs.cn/static/images/logos/nodejs-green.png";

          //request

          request

          .get(URL)

          //監(jiān)聽response

          .on('response', function(res) {

          console.log(res.statusCode); // 200

          console.log(res.headers['content-type']); // 'image/png'

          console.log(res.headers['content-length']);

          //打印接受的數(shù)據(jù)大小

          res.on('data', function(data){

          console.log('接受到數(shù)據(jù)' + data.length )

          })

          })

          //監(jiān)聽錯誤信息

          .on('error', function(error){

          consloe.log(error);

          })

          //以流的形式寫入創(chuàng)建的test.png文件

          .pipe(fs.createWriteStream('test.png'));

          response.writeHead(200);

          response.write('請前往同級目錄下查看下載內(nèi)容');

          response.end();

          }

          exports.home=home;

          exports.upload=uploads;

          exports.download=downloads;

          2.4 程序入口調(diào)用<待補充>

          //引用模塊

          var server=require('./server');

          var router=require('./router');

          var handler=require('./handler');

          var formidable=require('formidable');

          //調(diào)用具體方法

          var method={};

          method['/']=handler.home;

          method['/home']=handler.home;

          method['/upload']=handler.upload;

          //交給服務(wù)器模塊處理

          server.start(router.route, method);

          2.5 首頁中上傳模塊HTML文件 <待補充>

          最早的HTTP協(xié)議中是不支持文件上傳的,在1995年制定的rfc1867規(guī)范中,在HTTP POST請求的內(nèi)容類型Content-Type

          中擴展了multipart/form-data

          類型,該類型用于向服務(wù)器發(fā)送二進制數(shù)據(jù),以便支持文件的上傳。

          <html>

          <head>

          <meta charset="UTF-8">

          <title>Document</title>

          </head>

          <body>

          //上傳文件時需要通過enctype

          屬性將編碼方式設(shè)置為multipart/form-data

          <form action="/upload", enctype="multipart/form-data" method="post">

          <input type="file" name="upload" multiple="multipart">

          <input type="submit" value="提888交">

          </form>

          <form action="/download", enctype="multipart/form-data" method="get">

          <input type="submit" value='下載'>

          </form>

          </body>

          </html>


          者:訣九 前端名獅

          轉(zhuǎn)發(fā)鏈接:https://mp.weixin.qq.com/s/BMg8bFUwa4gmm6v2acAe7Q


          主站蜘蛛池模板: 日本无码一区二区三区白峰美| 中文字幕无码一区二区三区本日| 国产大秀视频一区二区三区| 日韩亚洲AV无码一区二区不卡| 精品国产亚洲一区二区在线观看| 国产情侣一区二区三区| 精品视频无码一区二区三区| 日韩综合无码一区二区| 国产成人欧美一区二区三区| 国产激情一区二区三区 | 国产精品一区二区久久精品| 无码毛片一区二区三区视频免费播放| 91麻豆精品国产自产在线观看一区| 国产成人精品久久一区二区三区| 亚洲人成网站18禁止一区| 无码少妇一区二区性色AV| 国产综合精品一区二区| 麻豆AV一区二区三区| 一区二区三区视频在线播放| 91视频一区二区三区| 国产日韩一区二区三区在线播放| 久久国产精品无码一区二区三区 | 东京热无码av一区二区| 一区二区视频在线免费观看| 人妻无码一区二区三区| 亚洲一区二区三区无码影院| 中文字幕一区二区三区有限公司| 久久精品国产第一区二区| 真实国产乱子伦精品一区二区三区| 久久精品国产一区二区三区不卡| 国产av熟女一区二区三区| 国产无线乱码一区二三区| 中文字幕精品一区二区日本| 国产日韩精品视频一区二区三区| 日韩aⅴ人妻无码一区二区| 亚洲片国产一区一级在线观看 | 国产一区二区三区播放| 无码一区二区三区亚洲人妻| 亚洲第一区精品观看| 无码人妻久久久一区二区三区| 亚洲一区二区三区在线观看网站 |