NODE - Connect+http+https+token

779 阅读24分钟

一、http模块的简单介绍

node.js当中的http内置模块可以用于创建http服务器与http客户端。 const http = require('http');

1.1.创建http服务器

虽然Node.js中的http核心模块可以用来实现web服务器,但要做很多工作,例如要检测每个文件的content type 因此我们决定用Connect模块,非常流行的Express web框架就是建立在Connect之上的.

var server = http.createServer((req,res)=>{
});

使用http的.createServer()方法可以用于返回一个http服务器实例,用自定义的server变量来接收。当该服务器每次接收到客户端的请求时触发调用其内部的回调函数,客户端每访问一次,都会触发调用一次。该回调函数有两个参数,req和res,顺序不可颠倒,req表示请求request,res表示响应response。

该回调函数内部语句的一定要有res.end();,因为如果没有,浏览器会认为一直没有得到服务器的响应,则浏览器一直会处于被挂起的状态,此时浏览器内部有一个超时机制,一旦超时,则会报告错误。

该回调函数当中的常用代码语句有:
设置响应头,res.writeHead(状态码,{});
其中HTTP状态码常用的有200(成功返回)、404(找不到该页面,返回错误)等。
第二个参数传入一个对象,用于设置响应文本的渲染解析类型。
如常用的有
对于html代码设置为,res.writeHead(200,{"Content-Type":"text/html;charset=UTF8"});
对于css文件的设置为res.writeHead(200,{"Content-Type":"text/css"});
对于图片的设置为res.writeHead(200,{"Content-Type":"image/jpg"});
对于纯文本的设置为res.writeHead(200,{"Content-Type":"text/plain"});
设置返回的内容,res.write('');

1.2.让该服务器监听特定的端口号

用server这个自定义的变量来表示创建的服务器来监听某个指定的端口号。server.listen(3000,'127.0.0.1');外界客户端可以通过这个ip地址和端口号来访问这个服务器。

此时表示该服务器处于挂起的状态,此时在浏览器当中输入对应的ip地址与端口号即可得到服务端响应的内容。

1.3.完整的示例代码:

const http = require('http');
const url = require('url');
const qs = require('qs');
var server = http.createServer((req,res)=>{
	const { method} = req; 
    res.writeHead(200,{"Content-Type":"text/html;charset=UTF8"});
    res.write('hello world');
   // const urlJson = url.parse(req.url);
   //  var query = qs.parse(urlJson.query);
    // console.log(query);

    const urlJson2 = url.parse(req.url,true);  
    console.log(urlJson2.query)

      if (method == "GET" && url == "/users") { 
        res.setHeader("Content-Type", "application/json"); 
        res.end(JSON.stringify([{ name: "tom", age: 20 }])); 
     } 

        res.end();
});
server.listen(3001);
console.log('listen 3001');

二、观察http协议以及发展历史

curl -v www.baidu.com

http发展历史:

版本产生时间内容发展现状
HTTP/0.91991年不涉及数据包传输,规定客户端和服务器之间通信格式,只能GET请求没有作为正式的标准
HTTP/1.01996年传输内容格式不限制,增加PUT、PATCH、HEAD、 OPTIONS、DELETE命令正式作为标准
HTTP/1.11997年持久连接(长连接)、节约带宽、HOST域、管道机制、分块传输编码2015年前使用最广泛
HTTP/22015年多路复用、服务器推送、头信息压缩、二进制协议等逐渐覆盖市场

多路复用:通过单一的HTTP/2连接请求发起多重的请求-响应消息,多个请求stream共享一个TCP连接,实现多留并行而不是依赖建立多个TCP连接。

2.1 管道机制(Pipelining)

HTTP 1.1 引入了管道机制(Pipelining),即客户端可通过同一个TCP连接同时发送多个请求。如果客户端需要请求两个资源,以前的做法是在同一个TCP连接里面,先发送A请求,然后等待服务器做出回应,收到后再发出B请求;而管道机制则允许浏览器同时发出A请求和B请求,但是服务器还是按照顺序,先回应A请求,完成后再回应B请求。

2.2 什么是多路复用?

在 HTTP 1.0 中,发起一个请求是这样的: 浏览器请求 url -> 解析域名 -> 建立 HTTP 连接 -> 服务器处理文件 -> 返回数据 -> 浏览器解析、渲染文件 

这个流程最大的问题是,每次请求都需要建立一次 HTTP 连接,也就是我们常说的3次握手4次挥手,这个过程在一次请求过程中占用了相当长的时间,而且逻辑上是非必需的,因为不间断的请求数据,第一次建立连接是正常的,以后就占用这个通道,下载其他文件,这样效率多高啊!

为了解决这个问题, HTTP 1.1 中提供了 Keep-Alive,允许我们建立一次 HTTP 连接,来返回多次请求数据。

虽然 HTTP 1.1 默认启用长TCP连接,但所有的请求-响应都是按序进行的(这里的长连接可理解成半双工协议。即便是HTTP 1.1引入了管道机制,也是如此)。复用同一个TCP连接期间,即便是通过管道同时发送了多个请求,服务端也是按请求的顺序依次给出响应的;而客户端在未收到之前所发出所有请求的响应之前,将会阻塞后面的请求(排队等待),这称为"队头堵塞"(Head-of-line blocking)。

HTTP/2复用TCP连接则不同,虽然依然遵循请求-响应模式,但客户端发送多个请求和服务端给出多个响应的顺序不受限制,这样既避免了"队头堵塞",又能更快获取响应。在复用同一个TCP连接时,服务器同时(或先后)收到了A、B两个请求,先回应A请求,但由于处理过程非常耗时,于是就发送A请求已经处理好的部分, 接着回应B请求,完成后,再发送A请求剩下的部分。HTTP/2长连接可以理解成全双工的协议。

三、https协议

https协议:超文本传输安全协议

是一种通过计算机网络进行安全通信的传输协议。HTTPS经由HTTP进行通信,但利用SSL/TLS来加密数据包。HTTPS开发的主要目的,是提供对网站服务器的身份认证,保护交换数据的隐私与完整性。这个协议由网景公司(Netscape)在1994年首次提出,随后扩展到互联网上。

简单来说,HTTPS 是 HTTP 的安全版,是使用 SSL/TLS 加密的 HTTP 协议。通过 TLS/SSL 协议的的身份验证、信息加密和完整性校验的功能,从而避免信息窃听、信息篡改和信息劫持的风险。

  • SSL(Secure Socket Layer) 安全套接层
  • TLS(Transport Layer Security) 传输层安全

3.1 什么是HTTPS?

《图解HTTP》这本书中曾提过HTTPS是身披SSL外壳的HTTP。HTTPS是一种通过计算机网络进行安全通信的传输协议,经由HTTP进行通信,利用SSL/TLS建立全信道,加密数据包。HTTPS使用的主要目的是提供对网站服务器的身份认证,同时保护交换数据的隐私与完整性。 PS:TLS是传输层加密协议,前身是SSL协议,由网景公司1995年发布,有时候两者不区分。

HTTPS 提供了加密 (Encryption)、认证 (Verification)、鉴定 (Identification) 三种功能

  • 私密性(Confidentiality/Privacy): 也就是提供信息加密,保证数据传输的安全;保证信息只有张三和李四知道,而不会被窃听。
  • 可信性(Authentication): 身份验证,主要是服务器端的,确认网站的真实性,有些银行也会对客户端进行认证;用来证明李四就是李四。
  • 完整性(Message Integrity): 保证信息传输过程中的完整性,防止被修改;李四接收到的消息就是张三发送的。 HTTPS就是在应用层和传输层中间加了一道验证的门槛以保证数据安全

3.2 SSL/TLS 协议

SSL ( secure socket layer )安全套接字层:

SSL协议由Netscape (网景)公司开发,第一个版本未发布过;第二二版在 1994年11月发布,但是失败了;第三版SSL (V3)在1995年发布。SSL3很成功, 近 几年SSL3逐步被淘汰了。

TLS ( transport layer security )传输层安全: 1996年5月,国际标准化组织的TLS工作组把SSL从Netscape迁移至IETF。 TLS 1.0于1999年1月推出,尽管与SSL 3相比修改并不大; 2006年4月TLS 1.1发布; 2008年8月TLS1.2发布; 2014年左右开始筹划TLS 1.3版本,TLS 1.3协议版本于 2018年3月21日完成;不过没有广泛的使用,配套的支持与服务还没有完善和铺 开。目前使用最广的是TLS1.2。

在最初设计互联网的时候,是没有考虑到信息安全方面的问题,使得通信协 议本身不安全。所以才开发出TLS来实现加密传输,确保信息安全。

3.3 为什么要配置SSL?

由于IPV4代理和各种网络路由等技术原因,部分地区,部分网络http访问域名可能存在被恶意劫持现象;比如打开网页出现一些莫名其妙的广告,点击页面跳转到其他第三方网站等。为了减少被劫持,https是非常有必要的,SSL证书应该成为每一个网站的必备buff。 参考: www.yimenapp.com/ssl.html

http "调用" SSL/TLS中的加密算法实现保密传输。https只能说是一种应用层协议; SSL加密HTTP内容,默认使用443端口 进行传输,SSL还可以加密Email默认使用995、465端口。 任何一一个应用层协议(http smtp ftp等)都可以“调用" TLS/SSL来加密其明文数据。所以简单有效的总结是: https= http+ SSL/ TLS

3.4 http和https的 11 个区别

https 已经是大势所趋,但对https 和http 之间的区别还不是特别清楚,本文用表格方式告诉您https对比http的优势。

httpVShttps
明文传输,网站或相关服务与用户之间的数据交互无加密,极易被监听,破解甚至篡改。传输方式在 HTTP 下加入了 SSL 层,是数据传输变成加密模式,从而保护了交换数据隐私和完整性,简单来说它就是安全版的 HTTP。
无任何身份认证,用户无法通过http辨认出网站的真实身份。身份认证经过CA多重认证,包括域名管理权限认证,单位身份合法性确认等。EV证书甚至可以直接在浏览器地址栏显示单位名称,提升用户体验。
无任何使用成本,所有网站默认即 http 模式。实现成本需要申请SSL证书来实现https,价格几百元到上万元不等,详见:SSL证书选购
80端口连接端口443端口
提示网站不安全:当您的网站上有类似注册登陆等表单时,用户一旦进行输入,Chrome浏览器便红色高亮显示“不安全”:浏览器兼容性提示网站连接是安全的当您申请的是“EVSSL证书”时,浏览器地址栏会直接显示您的单位名称,可显著提升网站用户的信任度和单位形象
对http网站无任何优待。SEO优化百度谷歌等官方声明提高 https 网站的排名权重。
极易被黑客或者恶意的同行进行流量劫持。网站劫持隐私信息加密,防止流量劫持
访问速度根据网站服务器配置和客户端的浏览环境而定。访问速度在同样配置的服务器以及客户端浏览环境下,可明显提高网页加载速度。
当网站需要与第三方平台进行对接时,通常不接受http这种连接。例如微信小程序,苹果ATS,抖音上做广告等等。数据对接微信小程序,抖音,苹果等等越来越多的平台只接受https这种加密的安全链接。
经常因为没有https,而被各个浏览器或者其他平台显示风险警告,导致损害用户的信任度。网站形象为网站的用户营造安全的浏览环境,是网站的基本责任,也是赢得用户信赖的一个重要因素。
无任何风险保障,当网站数据传输被截取导致重大损失时,只有网站运营者自己承担。风险保障拥有10万-175万美元的商业保险,当网站数据传输被破解时,有巨额的保障额度。

四、使用nodejs搭建HTTPS server

利用OpenSSL 创建https证书

OpenSSL是一个强大的安全套接字层密码库,Apache使用它加密HTTPS,OpenSSH使用它加密SSH,但是,你不应该只将其作为一个库来使用,它还是一个多用途的、跨平台的密码工具。

TLS是一系列的协议和标准,位于应用层和传输层之间起到将数据加密作用;通常说的SSL/TLS其实是实现了算法和协议的库,这个库提供加密的功能,应用层调用这些功能。

在Linux中的openssl是SSL/TLS和多种加密算法的开源实现它实现了几乎所有的加密算法,功能十分强大,使用十分广泛。

openSSL包括: libcrypto实现算法; libssI实现TLS/SSL协议的库,libssI是基于会话的,实现了身份认证数据加密,会话完整性等。使用openssl也可以模拟一个证书发布机构,openSSL的命令行工 具是openssl。

mkdir https
cd https
openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout key.pem -out cert.pem
US
Califormia
Francisco
noyanse
noyanse
localhost 这里可以填域名
noyanse@163.com

req  ------> 用于请求创建一个证书文件
new  ------>表示创建的是新的证书
x509 ------>表示定义证书的格式为标准格式
key  ------>表示调用的私钥文件信息
out  ------>表示输出证书文件信息
days ------->证书的有效期限,单位是day(天),默认是365天

index.js测试代码

const https = require('https');
const fs = require('fs');


const key = fs.readFileSync('./key.pem');
const cert = fs.readFileSync('./cert.pem');

const options = {
  key:key,
  cert:cert
};

https.createServer(options, (req, res) => {
  
  res.writeHead(200);
  res.end('hello world-----\n');


}).listen(8000);

参考: www.cnblogs.com/yjiu1990/p/…

五、Connect介绍

Connect是一个node中间件(middleware)框架。如果把一个http处理过程比作是污水处理,中间件就像是一层层的过滤网。每个中间件在http处理过程中通过改写request或response的数据、状态,实现了特定的功能。

5.1 尝试做一个最简单的web服务器

var connect = require('connect');
var app = connect()
    .use(function (req, res) {
        res.end('hello world\n');
    })
    .listen(3000);

5.2 url & qs

安装: npm install url qs 或者 yarn add url qs

url 顾名思义,就是为客户端请求地址的一个解析。而 qs 则是在 url 处理结果的基础上再进行字段解析。

const url = require('url');
const app= require('connect');
const qs = require('qs');
app()
    .use(function(req, res) {

       // const urlJson = url.parse(req.url);
       // const query = qs.parse(urlJson.query);


        const urlJson = url.parse(req.url,true);
        console.log(urlJson.query.name);


    })
.listen(3000);

六、 Connect 工作机制

1.自定义中间件 2.use() 函数支持链式调用 3.中间件的顺序问题

在Connect中,中间件组件是一个函数,它拦截HTTP服务器提供的请求和响应对象,执行逻辑,或者结束响应,或者把它传递给下一个中间件组件。

Connect分配器会依次调用所有附着的中间件组件,直至其中一个组件决定响应该请求,如果知道中间件组件列表末尾还是没有组件决定响应,程序会返回404作为响应。(ex1这个程序没有中间件组件,故会返回404 Not Found状态码响应他接收到的所有HTTP请求。)

Connect中,中间件组件是一个JS函数,接收3个参数

a. 请求对象(req) b. 响应对象(res) c. 通常会命名为next的参数:一个回调函数,表明当前中间件已经执行完毕,可以执行下一个中间件组件

6.1 需求: 简单的 hello world + 日志log

var connect = require("connect");
var app = connect()
          .use(logger)
          .use(hello)
          .listen(3000);
function logger(req, res, next) {
    console.log(req.method + ' ' + req.url);
    next(); //执行下一个中间件
}
function hello(req, res) {
    res.setHeader('Content-type', 'text/plain');
    res.end("hello world");
}

6.2 中间件的顺序问题

var app = connect()
          .use(hello)
          .use(logger)
          .listen(3000);

先执行了hello的中间件,响应了HTTP的请求,同时没有调用next(),控制权不会回到分配器去调用下一个中间件,所以logger中间件不会调用。

注意:当一个中间件组件不调用next()时,命令链中的其他中间件都不会被调用。

6.3 跨域:浏览器同源策略引起的接口调用问题

.index.html中请求位于3000服务器的接口 axios.get("http://localhost:3001/users")

常用解决方案:

  1. JSONP(JSON with Padding),前端+后端方案,绕过跨域 前端构造script标签请求指定URL(由script标签发出的GET请求不受同源策略限制),服务器返回一个函数执行语句,该函数名称通常由查询参callback的值决定,函数的参数为服务器 返回的json数据。该函数在前端执行后即可获取数据。
  2. 代理服务器 请求同源服务器,通过该服务器转发请求至目标服务器,得到结果再转发给前端。 前端开发中测试服务器的代理功能就是采用的该解决方案,但是最终发布上线时如果web应 用和接口服务器不在一起仍会跨域。
  3. CORS(Cross Origin Resource Share) - 跨域资源共享,后端方案,解决跨域 原理:cors是w3c规范,真正意义上解决跨域问题。它需要服务器对请求进行检查并对响应头做相应处理,从而允许跨域请求。

具体实现:

  • 响应简单请求: 动词为get/post/head,没有自定义请求头,Content-Type是application/x-www-form-urlencoded,multipart/form-data或text/plain之一,通过添加以下响应头解决:
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3001')
  • 响应preflight请求,需要响应浏览器发出的options请求(预检请求),并根据情况设置响应头:
else if (method == "OPTIONS" && url == "/users") { 
res.writeHead(200, { 
"Access-Control-Allow-Origin": "http://localhost:3001", 
"Access-Control-Allow-Headers": "X-Token,Content-Type", 
"Access-Control-Allow-Methods": "PUT" 
}); 
res.end(); 
}

该案例中可以通过添加自定义的x-token请求头使请求变为preflight请求

// index.html 
axios.get("http://localhost:3000/users", {
headers:{'X-Token':'jilei'}
})

则服务器需要允许x-token,若请求为post,还传递了参数:

// index.html 
axios.post("http://localhost:3000/users", {foo:'bar'}, {headers: 
{'X-Token':'jilei'}}) 
// http-server.js 
else if ((method == "GET" || method == "POST") && url == "/users") { }

则服务器还需要允许content-type请求头

  • 如果要携带cookie信息,则请求变为credential请求:

// 预检options中和/users接口中均需添加 res.setHeader('Access-Control-Allow-Credentials', 'true');

function proxy(req, res,next){

        //跨域处理
        // 注意: http://192.168.1.29:8080为静态资源访问的地址
        res.setHeader('Access-Control-Allow-Origin', 'http://192.168.1.29:8080'); 
//      res.setHeader('Access-Control-Allow-Origin', '*');  //允许任何源
        //允许任何源 ,如果服务器要求浏览器发送 Cookie,这是不能设置为*

        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');  //允许任何方法
        // res.setHeader('Access-Control-Allow-Methods', '*'); 

         res.setHeader('Access-Control-Allow-Headers', 'X-Token,Content-Type')
        // res.setHeader('Access-Control-Allow-Headers', '*');   //允许任何类型

        next();  //next 方法就是一个递归调用

}

七、 connect常用中间件

connect 是一个非常轻量级 Node 中间件框架,对于一个中小型项目,connect 需要配合很多三方模块才能完善服务器逻辑。所以现在的工程中,为了简化开发,往往会采用它的升级版 express ,或是 koa 作为基础框架进行扩展。当然,在使用这些框架之前,对于最原始的细节,同样也是需要去仔细钻研的。

7.1 body-parser

安装: yarn add body-parser 用来解析请求主体

Node 或是使用 Connect 在处理请求数据时,是需要解析 req 的,body-parser 中间件恰好提供了这一操作。

  • bodyParser()中间件的作用是给req添加body属性,可以用来解析JSON、x-www-form-urlencoded和multipart/form-data请求
  • body-parser 只处理 POST 请求
  • body-parser 模块导出一个对象,上面有两个方法 urlencoded 和 json,分别处理表单提交和 json 格式的请求体参数
  • 如果是multipart/form-data请求,比如文件上传,则还有req.files 对象
  • 这是个非常有用的组件,实际上它整合了其他三个更小的组件:json(), urlencoded(), 和multipart()
  • 旧版本的 body-parser 还可以处理文件上传(现在需要使用 formidable 一类的文件上传模块)。

当请求体解析之后,解析值会被放到req.body属性中,当内容为空时候,为一个空对象{} ---bodyParser.json()--解析JSON格式 ---bodyParser.raw()--解析二进制格式 ---bodyParser.text()--解析文本格式 ---bodyParser.urlencoded()--解析文本格式

const app= require('connect')();
const bodyParser = require('body-parser');
app
    .use(function(req, res, next) {
        console.log(req.body); // undefined
        next();
    })
    //解析 application/json,最后保存的数据都放在req.body对象上
    .use(bodyParser.json())   //JSON解析
    // 解析 application/x-www-form-urlencoded
    .use(bodyParser.urlencoded({extended: true})) 
    .use(function(req, res) {
        console.log(req.body); // post 请求数据
        res.end('hello world\n');
    })
.listen(3000);

注意post请求的时候可以通过req.body获取参数,但是url不行得 通过url去解析

// 写成中间件形式
function getParamsMiddle(req, res,next) {
    if(req.method.toLocaleLowerCase()=='post') {
        query = req.body;
    } else {
        const urlJson = url.parse(req.url,true);
        query = urlJson.query;
    }
    req.query = query;
    console.log('参数');
    next();
}

使用:

...
 .use(getParamsMiddle)
 ...

不仅仅是 connect ,在 express 和 koa 中,同样也有 body-parser 中间件。

7.2. cookie-parser & jsonwebtoken

和 body-parser 类似,cookie-parser 将来自浏览器的 cookie 请求体转化到 req.cookies 上。它可以处理常规 cookie 和 签名 cookie。

在现在的前后端通信,特别是第三方认证盛行的模式下,cookie 和 sesssion 已不在是主流,再加之为了遵守 http 无状态的本质,往往会选择 token 方式进行认证。而 jsonwebtoken 恰好能让我们的 Node 程序实现这一认证。

7.3 什么是JSON Web Token?

JSON Web Token 是一个开放标准协议,它定义了一种紧凑和自包含的方式,它用于各方之间作为JSON对象安全地传输信息。

它有如下优点:

  1. 可以适用于分布式的单点登录场景。
  2. 可以使用跨域认证解决方案。
  3. jwt实现自动刷新token的方案(待认证)。
const jwt = require('jsonwebtoken');
/**
 * 对验证成功地请求体进行签名
 * obj 被签名的主体,参数必须是一个object、Buffer、或 string.
 * signedText 密钥,是包含HMAC算法的密钥或RSA和ECDSA的PEM编码私钥的string或buffer。
 * options 签名设置,如过期日期

 const token = jwt.sign(obj, signedText, options);
*/ 

options 参数有如下值:

algorithm:加密算法(默认值:HS256)
expiresIn:以秒表示或描述时间跨度zeit / ms的字符串。如60"2 days""10h""7d",含义是:过期时间
notBefore:以秒表示或描述时间跨度zeit / ms的字符串。如:60"2days""10h""7d"
audience:Audience,观众
issuer:Issuer,发行者
jwtid:JWT ID
subject:Subject,主题
noTimestamp
header

nodejs实现的jwt的github代码(github.com/auth0/node-…)

我们在项目中使用node中jsonwebtoken来生成一个JWT的demo了,在index.js 代码如下:

//生成一个token
const jwt = require('jsonwebtoken');
const secret = 'abcdef';
let token = jwt.sign({
  name: 'laney'
}, secret, (err, token) => {
  console.log(token);
});

然后我们进入项目中的目录,执行 node index.js 执行后看到命令行中会打印中的token了,如下所示:

当然我们也可以设置token的过期时间,比如设置token的有效期为1个小时,如下代码:

// 生成一个token
const jwt = require('jsonwebtoken');

const secret = 'abcdef';
// 设置token为一个小时有效期
let token = jwt.sign({
  name: 'kongzhi',
  exp: Math.floor(Date.now() / 1000) + (60 * 60)
}, secret, (err, token) => {
  console.log(token);
});

Date.now() : 以毫秒为单位 返回值:返回自1970年1月1日00:00:00 UTC以来经过的毫秒数。

注意:exp(过期时间) 只有当payload是object字面量时才可以设置。如果payload不是buffer或string,它会被强制转换为使用的字符串JSON.stringify()。

var d = Date(Date.now());
// 转换日期字符串中的毫秒数
a = d.toString();
// 输出当前日期
document.write("当前日期是:" + a);

7.4 jwt.verify(token, secretOrPrivateKey, [options, callback])

该方法是验证token的合法性

语法:

/**
 * 进行验证
 * client_token 客户端传来的 token 值
 * signedText 密钥
*/
jwt.verify(client_token, signedText, function(err, decode) {
    if (err) return;
    console.log(decode);
    // 验证成功后 token 信息
});

比如上面生成的token设置为1个小时,生成的token为:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoibGFuZXkiLCJpYXQiOjE1OTY0NDczNzB
9.pmTWC2jNjyGuKQ2Nk_DEzXebf8bIhCGPkQGEb94obI4

下面我们使用 jwt.verify来验证一下:

const jwt = require('jsonwebtoken');
const token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1lIjoibGFuZXkiLCJpYXQiOjE1OTY0NDczNzB
9.pmTWC2jNjyGuKQ2Nk_DEzXebf8bIhCGPkQGEb94obI4';
const secret = 'abcdef';
jwt.verify(token, secret, (error, decoded) => {
  if (error) {
    console.log(error.message);
  }
  console.log(decoded);
});

7.5. serve-static

首先,由于Node.js的事件驱动机制类似Nginx,虽然,Node.js主要是为动态页面服务的服务器,但是我们也可以用作像Nginx Apache那样静态Html页面服务器,主要是没有Nginx那么多配置优化,直接简单启动就可以了,步骤如下:

  1. 安装 : yarn add serve-static connect

  2. 在当前bin目录创建一个文件名server.js的文件,内容如下

var connect = require('connect');
var serveStatic = require('serve-static');
connect().use(serveStatic(__dirname)).listen(8080);  

  1. 运行NodeJS node server.js

注意,在bin目录下创建index.html和其他静态资源如图片以后,就可以通过浏览器访问你的文件:http://localhost:8080/index.html

配置

Index.js配置如下:
var connect = require('connect');  //创建连接
var bodyParser = require('body-parser');   //body解析
var cookieParser = require('cookie-parser');

var app = connect()
    .use(bodyParser.json())   //JSON解析
    .use(bodyParser.urlencoded({extendedtrue}))
    .use(cookieParser())
增加跨域的处理
.use(function (req, res, next{
        //跨域处理
        // Website you wish to allow to connect
        res.setHeader('Access-Control-Allow-Origin''*');  //允许任何源
        // Request methods you wish to allow
        res.setHeader('Access-Control-Allow-Methods''GET, POST, OPTIONS, PUT, PATCH, DELETE');  //允许任何方法
        // Request headers you wish to allow
        res.setHeader('Access-Control-Allow-Headers''*');   //允许任何类型
        res.writeHead(200, {"Content-Type""text/plain;charset=utf-8"});    //utf-8转码
        next();  //next 方法就是一个递归调用
})

添加一个 简单的接口
.use('/info'function(req, res, next{
        //response 响应   request请求
        // 中间件
        console.log(req.method + ' ' + req.url);
        // console.log(req.body);
        // console.log(req.originalUrl, req.url);

         // Cookies that have not been signed
         console.dir('Cookies: ', req.cookies)
       
         // Cookies that have been signed
         console.log('Signed Cookies: ', req.signedCookies)

        var data={
                "code""200",
                "msg""success",
                "result": [{
                    "id":1,
                    "name""sonia",
                    "content""广告投放1"
                },
                {
                    "id":2,
                    "name""ben",
                    "content""广告投放2"
                },
                {
                    "id":3,
                    "name""lili",
                    "content""广告投放3"
                }]
            }
            res.end(JSON.stringify(data));
            next();  
});

app.listen(3000);

运行

依赖安装完成后输入node server-run.js 接口访问可通过http://localhost:3000/info

八、如何查看接受参数

POST请求

九、Nodejs 热加载

方式一、supervisor sudo npm install -g supervisor #安装 supervisor app.js #启动

方式二、hotnode sudo npm -g install hotcode #安装 hotnode app.js #启动

方式三: yarn global add nodemon nodemon app.js

十、使用http-server开启一个本地服务器

下载安装

npm install http-server -g

开启 http-server服务

终端进入目标文件夹,然后在终端输入: http-server -c-1 (⚠️只输入http-server的话,更新了代码后,页面不会同步更新)

关闭 http-server服务

按快捷键CTRL-C 终端显示^Chttp-server stopped.即关闭服务成功。

十一、formidable处理POST方式上传的文件或图片

form.html文件

<form action="http://192.168.155.1:3000/dopost" method="POST" enctype="multipart/form-data">
   <p><input type="file" name="uploadImg"></p>
   <p><input type="submit" value="提交"></p>
</form>

当表单提交的过程中涉及文件或图片上传,则一定要设置表单头,即在form标签上加上固定写法的属性为enctype="multipart/form-data",否则文件或图片会上传失败。其中,当中的name属性一定要赋值。

下载并引包

npm install formidable 再通过const formidable = require('formidable');来引包。

要正确处理上传的文件,并接收到文件的内容,需要把表单的 enctype 属性设为 multipart/form-data。Node 社区有几个可以完成这个任务的模块,formidable 就是之一。简单使用如下:


const formidable = require('formidable');
const app= require('connect')();
app
    .use(function(req, res) {
        if (req.method == 'POST') {
            const form = new formidable.IncomingForm();
            // 上传路径
            form.uploadDir = __dirname + '/public';
            form.parse(req, function(err, fields, files) {
                res.end('upload complete!');
            });
        }
    })
    .listen(3000);

当要使用formidable来处理上传的图片时,常用的代码段为:

const formidable = require('formidable');
var connect = require('connect')
var app = connect();

app.use('/upload/img',function(req, res, next){
    var form = new formidable.IncomingForm();
    form.encoding='utf-8';
    form.uploadDir = path.join(__dirname,'./static');
    form.keepExtensions=true;
    form.parse(req,function(err,fields,files){
        console.log(files)
        if (err){
            return;
        };
        var size=parseInt(files.uploadImg.size);
        if (size>1024*1024){
            res.send("图片过大!")
            fs.unlink(files.uploadImg.path);
            return;
        };
        res.end('upload success');
        next();
    });
   
})
.listen(3000);