合规国际互联网加速 OSASE为企业客户提供高速稳定SD-WAN国际加速解决方案。 广告
>[success] # 监听主机和端口号 1. 我们在启动一个服务时,需要指定这个服务的监听地址(host)和监听端口(port),用于接收来自其他设备或进程的连接请求。**通过ip:port的方式发送到我们监听的Web服务器上时** | 地址 | 含义 | | --- | --- | | localhost | 指本机。通常被解析为 127.0.0.1 地址,用于指向本机上单个应用程序或进程内部的通信接口。 | | 127.0.0.1 | 本机回环地址。它指向的是本机本地的一个虚拟网卡,用于在本机上的进程之间进行网络通信。 | | 0.0.0.0 | 指本机上所有 IP 地址,用于让服务监听在本机的所有网络接口上等待连接请求,可以对其他设备或进程对于本机的任何 IP 地址发起的连接请求进行响应。有时也成为通配符地址。 **监听IPV4上所有的地址** ,再根据端口找到不同的应用程序| | 网卡对应 IP | 网卡对应的 IP 地址,例如 192.168.1.100。如果要监听来自本地网络中其他设备对于本机的连接请求,可以使用网卡对应的 IP。 | 2. **关于监听端口**,端口占用两个字节 **256 * 256 = 65536** ,也就 **0 - 65536** 的端口号都能使用,但是一般 **0-1024**的都是特殊端口,推荐自定义的范围在**1025~65535**之间的端口 * 以node 为例 ~~~ const http = require('http'); const server1 = http.createServer((req, res) => { // 请求处理逻辑 }); // 监听在 localhost:8080 server1.listen(8080, 'localhost', () => { console.log('Server is listening on localhost:8080'); }); const server2 = http.createServer((req, res) => { // 请求处理逻辑 }); // 监听在 127.0.0.1:8081 server2.listen(8081, '127.0.0.1', () => { console.log('Server is listening on 127.0.0.1:8081'); }); const server3 = http.createServer((req, res) => { // 请求处理逻辑 }); // 监听在 0.0.0.0:8082 包括回环地址 127.0.0.1 和其他网卡对应的 IP 地址 server3.listen(8082, '0.0.0.0', () => { console.log('Server is listening on 0.0.0.0:8082'); }); const server4 = http.createServer((req, res) => { // 请求处理逻辑 }); // 监听在 192.168.1.100:8083(假设网卡的 IP 是 192.168.1.100) server4.listen(8083, '192.168.1.100', () => { console.log('Server is listening on 192.168.1.100:8083'); }); ~~~ >[info] ## 创建 http服务 | API | 参数 | 介绍 | | --- | --- | --- | | http.createServer(\[requestListener\]) | requestListener(request, response) | 创建 Http 服务器实例,requestListener 为请求事件的回调函数 | | server.listen(port\[, hostname\]\[, backlog\]\[, callback\]) | port (Number):监听的端口号hostname (String):主机名backlog (Number):等待队列最大长度callback (Function):服务器启动后的回调函数 | 启动 Http 服务器,指定端口和主机名等配置信息 | * **传入一个回调函数,这个回调函数在 被调用时会传入两个参数**,`req:reques`t请求对象,包含请求相关的信息, `res:response`响应对象,包含我们要发送给客户端的信息; **请求对象常用属性和方法** | 属性/方法 | 描述 | | --- | --- | | `req.method` | 请求方法(例如 GET、POST、PUT 等) | | `req.url` | 请求 URL 的完整信息(包括协议、主机名、路径和查询参数等) | | `req.headers` | 请求头对象,由键值对构成,可通过属性名或`getHeader()`方法获取对应的值 | | `req.socket` | 底层套接字(socket)对象,可以用于查看底层传输协议的信息 | | `req.httpVersion` | 请求使用的 HTTP 版本号 | | `req.on('data', callback)` | 注册`data`事件的回调函数,用于接收消息主体的数据块 | | `req.on('end', callback)` | 注册`end`事件的回调函数,表明消息主体读取完毕 | **响应对象常用属性和方法** | 属性/方法 | 描述 | | --- | --- | | `res.statusCode` | 状态码(例如 200、404 等) | | `res.statusMessage` | 状态消息(例如 OK、Not Found 等) | | `res.setHeader(name, value)` | 设置响应头信息,用于声明服务器所发送的内容类型、编码等信息 | | `res.writeHead(statusCode[, statusMessage][, headers])` | 一次性写入相应头信息 | | `res.write(chunk[, encoding][, callback])` | 向客户端发送内容,可以多次调用 | | `res.end([chunk][, encoding][, callback])` | 结束响应,通常在数据发送完毕后调用 | >[danger] ##### 案例 ~~~ const http = require('http') // 创建http 服务 const server = http.createServer((req, res) => { /** * 传入一个回调函数,这个回调函数在 被调用时会传入两个参数 * req:request请求对象,包含请求相关的信息 * res:response响应对象,包含我们要发送给客户端的信息; */ // 1.url信息 console.log(req.url) // 2.method信息(请求方式) console.log(req.method) // 3.headers信息(请求信息) console.log(req.headers) // 设置响应头 res.setHeader('Content-Type', 'text/html;charset=utf-8') // 利用响应在页面输出内容, res: response对象 => Writable可写流,write 可以使用多次,但是最后一定要使用 end 来结束响应,否则客户端会一直等待 res.write('你好', 'utf-8', () => { console.log('发送成功') }) // 在每次响应结束后用end方法,才能保证结束响应,告诉客户端,我的话说完了,你可以呈递给用户了 res.end('结尾') }) // 可以监听多个端口 在没有指定host 默认启动的就是 0.0.0.0在同一个网段下的主机中,通过ip地址是可以访问的 server.listen(8080, () => { console.log('启动8080 端口服务: http://localhost:8080') }) ~~~ * 响应数据后使用`res.end()`来结束本次响应。在结束之前,你可以使用`res.write()`多次写入响应数据,但必须在最后使用`res.end()`来结束此次响应。否则客户端将一直等待服务器的响应数据,导致请求一直处于等待状态(**因为是流在使用流的时候要关闭**) ![](https://img.kancloud.cn/0e/12/0e1237b7beeba9ce0722524541cd2560_944x518.png) >[danger] ##### 设置响应头 1. `res.setHeader`:一次写入一个头部信息;/` res.writeHead`:同时写入header和status 2. 如果不规定响应头浏览器默认按照当前操作系统的默认编码去解析,win是gbk所以会出现请求后出现乱码的情况,text/plain 是普通文本,text/html是将html解析后展示,`setHeader('Content-Type', 'text/plain; charset=utf-8') `告诉浏览器用utf-8解析 ~~~ const http = require('http') // 1.创建server服务器 const server = http.createServer((req, res) => { // 设置header信息: 数据的类型以及数据的编码格式 // 1.单独设置某一个header // res.setHeader('Content-Type', 'text/plain;charset=utf8;') // 2.和http status code一起设置 res.writeHead(200, { 'Content-Type': 'application/json;charset=utf8;', }) // 3. statusCode // res.statusCode = 403 // 4. setHead 响应头 res.writeHead(401) const list = [{ name: '1', age: 18 }] res.end(JSON.stringify(list)) }) // 2.开启server服务器 server.listen(8000, () => { console.log('服务器开启成功~') }) ~~~ >[danger] ##### 获取请求连接中的参数 ~~~ const http = require('http') const url = require('url') const qs = require('querystring') // 1.创建server服务器 const server = http.createServer((req, res) => { // 1.参数一: query类型参数 // /home/list?offset=100&size=20 // 1.1.解析url const urlString = req.url const urlInfo = url.parse(urlString) // 1.2.解析query: offset=100&size=20 const queryString = urlInfo.query const queryInfo = qs.parse(queryString) console.log(queryInfo.offset, queryInfo.size) res.end('hello world aaaa bbb') }) // 2.开启server服务器 server.listen(8000, () => { console.log('服务器开启成功~') }) ~~~ >[danger] ##### 服务端获取请求头数据 1. keep-alive,http是基于TCP协议的,但是通常在进行一次请求和响应结束后会立刻中断,在http1.0中,如果想要继续保持连接 * 浏览器需要在请求头中添加connection: keep-alive; * 服务器需要在响应头中添加connection:keey-alive; * 当客户端再次放请求时,就会使用同一个连接,直接一方中断连接; 2. http1.1中,所有连接默认是connection: keep-alive的; * 不同的Web服务器会有不同的保持keep-alive的时间 * Node中默认是5s中 ~~~ const http = require('http') const url = require('url') // 1.创建server服务器 const server = http.createServer((req, res) => { console.log(req.headers) console.log(req.headers['content-type']) // cookie/session/token const token = req.headers['authorization'] console.log(token) res.end('查看header的信息~') }) // 2.开启server服务器 server.listen(8000, () => { console.log('服务器开启成功~') }) ~~~ >[danger] ##### 服务端获取请求体中数据 1. `req.on('data')`是 Node.js 中 HTTP 请求对象中的一个事件,用于获取 POST 方法提交的数据。 * 具体来说,当客户端向服务端发送一个 POST 请求时,请求数据会被包含在 HTTP 请求体中,而 Node.js 的`http`模块中的`req`对象(即 HTTP 请求对象)可以通过监听`'data'`事件来逐步获取请求体中的数据。这个事件会在每次获取到数据的时候触发,数据会以 Buffer 的形式作为回调函数的参数传递 ~~~ const http = require('http'); http.createServer((req, res) => { if (req.method === 'POST') { let postData = ''; // 获取客户端请求头里面的数据 req.on('data', chunk => { postData += chunk; }); req.on('end', () => { console.log(postData); res.end('Data received\n'); }); } else { res.end('Hello World\n'); } }).listen(3000); ~~~ 2. 创建了一个 HTTP 服务器,并在其中监听`'data'`事件和`'end'`事件。当发起 POST 请求时,服务端会在每次接收到数据时触发`'data'`事件,并将数据以 Buffer 的形式传入回调函数中。我们可以将这些数据片段拼接起来,得到完整的请求体数据。当请求体数据接收完毕时,`'end'`事件会被触发,我们可以在其回调函数中做出响应。若是 GET 请求,则直接响应`"Hello World\n"`。 ~~~ let postData = JSON.stringify({ 'msg': 'Hello World!' }); let options = { hostname: 'localhost', port: 3000, path: '/', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': postData.length } }; // 发起对服务端的请求数据 let req = http.request(options, res => { console.log(`statusCode: ${res.statusCode}`); res.on('data', chunk => { console.log(`BODY: ${chunk}`); }); }); req.on('error', error => { console.error(error); }); req.write(postData); req.end(); ~~~ >[info] ## 综合案例 >[danger] ##### 根据url访问模拟网站请求 ~~~ var http = require('http') // 1. 创建 Server var server = http.createServer() // 2. 监听 request 请求事件,设置请求处理函数 server.on('request', function (req, res) { console.log('收到请求了,请求路径是:' + req.url) console.log('请求我的客户端的地址是:', req.socket.remoteAddress, req.socket.remotePort) // res.end('hello nodejs') // 根据不同的请求路径发送不同的响应结果 // 1. 获取请求路径 // req.url 获取到的是端口号之后的那一部分路径 // 也就是说所有的 url 都是以 / 开头的 // 2. 判断路径处理响应 var url = req.url if (url === '/') { res.end('index page') } else if (url === '/login') { res.end('login page') } else if (url === '/products') { var products = [{ name: '苹果 X', price: 8888 }, { name: '菠萝 X', price: 5000 }, { name: '小辣椒 X', price: 1999 } ] // 响应内容只能是二进制数据或者字符串 res.end(JSON.stringify(products)) } else { res.end('404 Not Found.') } }) // 3. 绑定端口号,启动服务 server.listen(3000, function () { console.log('服务器启动成功,可以访问了。。。') }) ~~~ >[danger] ##### 利用文件的读取 1. 利用读取文件响应,其中响应到浏览器的内容,算然读取出来的的是16进制,但是res.end,既可以toString()一下,也可以省略 ~~~ var http = require('http') var fs = require('fs') var server = http.createServer() server.on('request', function (req, res) { // / index.html var url = req.url if (url === '/') { // 我们要发送的还是在文件中的内容 fs.readFile('../views/index.html', function (err, data) { if (err) { res.setHeader('Content-Type', 'text/plain; charset=utf-8') res.end('文件读取失败,请稍后重试!') } else { // data 默认是二进制数据,可以通过 .toString 转为咱们能识别的字符串 // res.end() 支持两种数据类型,一种是二进制,一种是字符串 res.setHeader('Content-Type', 'text/html; charset=utf-8') res.end(data) } }) } else if (url === '/xiaoming') { fs.readFile('../resource/ab2.jpg', function (err, data) { if (err) { res.setHeader('Content-Type', 'text/plain; charset=utf-8') res.end('文件读取失败,请稍后重试!') } else { // data 默认是二进制数据,可以通过 .toString 转为咱们能识别的字符串 // res.end() 支持两种数据类型,一种是二进制,一种是字符串 // 图片就不需要指定编码了,因为我们常说的编码一般指的是:字符编码 res.setHeader('Content-Type', 'image/jpeg') res.end(data) } }) } }) server.listen(3000, function () { console.log('Server is running...') }) ~~~ >[warning] ## 注意 >[danger] ##### 修改代码后帮自动自动服务 1. `nodemon`可以在检测到代码变更时自动重启 Node.js 服务 ~~~ npm install -g nodemon ~~~ 在启动服务时使用`nodemon`命令替代`node`命令即可 ~~~ nodemon app.js ~~~ 当修改完代码后保存文件,`nodemon`就会检测到变更并自动重启服务器,从而使新的代码生效。 >[danger] ##### 在访问过程中发现触发两次 1. 是因为通过浏览器请求时候,访问了`/favicon.ico`一次额外请求导致我们运行下面代码时候打印两次 ~~~ const http = require('http') // 1.创建server服务器 const server = http.createServer((req, res) => { console.log('服务器被访问~') res.end('hello world aaaa') }) // 2.开启server服务器 server.listen(8000, () => { console.log('服务器开启成功~') }) ~~~ 2. 因为上面代码是所有连接访问都会接受到,浏览器的默认`/favicon.ico ` 也额外接到了,可以通过判断`request `返回的指定`url `限制针对指定的条件返回,这样就会是数以自己的被打印出来