Node.js入门之http模块和dns模块

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
简介: 在nodejs中,http可以说是最核心的模块,借助http模块,可以几行代码就搞定一个超迷你的web server。学好http模块对于后面的web框架express、koa的学习也很有帮助。

http服务分为客户端和服务端。我们先来说说服务端。

服务端

创建HTTP服务器

http.createServer(fn)用来创建http服务器

const http = require("http");

const server = http.createServer((serverReq, serverRes) => {});

当服务器收到客户端的请求后就会进入该方法serverReq是请求对象,serverRes是服务器端响应对象。

启动HTTP服务器

server.listen(port,[host],[backlog],[callback]);用来启动服务器。

  • port 监听的端口号
  • host 监听的地址
  • backlog 指定位于等待队列中的客户端连接数
  • callback 回调函数
server.listen(3000, () => {
  console.log("服务启动啦")
})

关闭HTTP服务器

server.close()用来关闭http服务,并且还可以监听该事件。

const http = require("http");

const server = http.createServer(function (serverReq, serverRes) {
  const url = serverReq.url;
  serverRes.end("您访问的地址是:" + url);
});

server.on("close", () => {
  console.log("服务关闭啦");
});

server.listen(3000, () => {
  console.log("服务器端开始监听!");
  server.close();
});

监听服务器错误

server.on('error', (e)=>{
  console.log(e)
});

设置超时时间

通过server.setTimeout(msecs, callback)设置超时时间,超时后不可再复用已经建立的连接,需要发请求需要重新建立连接。默认超时时间是2分钟。

server.setTimeout(msecs, callback);

通过监听timeout事件来进行超时处理。

server.on('timeout',function(){
  console.log('连接已经超时');
});

服务端请求对象

服务端请求对象req它其实是http.IncomingMessage实例,我们通常会用它来获取headerurl
、参数等信息。

获取请求链接、http版本、请求方法、请求头部

const http = require("http");

const server = http.createServer((req, res) => {
  console.log("1、客户端请求url:" + req.url);
  console.log("2、http版本:" + req.httpVersion);
  console.log("3、http请求方法:" + req.method);
  // 这里使用JSON.stringify是为了方便在控制台查看,实际上是一个对象可以直接使用
  console.log("4、http请求头部" + JSON.stringify(req.headers));

  res.write("hello");
  res.end("world");
});

我们在浏览器键入http://localhost:3000/hello输出如下

image.png

获取get请求参数

既然有请求,那一定会有参数,我们先来说说获取get请求参数。

get请求的参数都会在url里面,我们一般会使用前面学习的url或者querystring模块进行处理。

const http = require("http");
const url = require("url");

const server = http.createServer((req, res) => {
  // 利用前面学习的url模块进行参数处理
  const params = url.parse(req.url, true);
  console.log(params.query);

  res.write("hello");
  res.end("world");
});

我们在浏览器键入http://localhost:3000/hello?name=randy输出如下

image.png

获取post请求参数

我们知道,get请求的参数是在浏览器路径里面,但是post请求的参数是在请求体里面,那这样我们怎么获取到参数呢?

这里就要用到请求对象req的一些事件了。

const http = require("http");

const server = http.createServer((req, res) => {
  let body = "";
  req.on("data", function (thunk) {
    body += thunk;
  });

  req.on("end", function () {
    console.log("post body is: " + body);
    res.end("ok");
  });
});

我们用postman构造一个post请求,http://localhost:3000传递参数name:jack输出如下

image.png

服务端响应对象

服务端响应对象,它其实是http.ServerResponse实例。

当接受到来自客户端的http请求后,用来向客户端返回响应内容,比如状态代码/状态描述信息、响应头部、响应主体。

设置状态代码、状态描述信息

我们可以通过res.statusCoderes.statusMessage来设置状态代码、状态描述信息。

当然你也可以直接使用设置头部方法res.writeHead来设置。相当于是一个简写。

const server = http.createServer((req, res) => {
  
  // 简写 res.writeHead(200, "ok")
  
  res.statusCode = 200;
  res.statusMessage = "ok";
  
  res.write("hello");
  res.end("world");
});

设置响应头

我们使用res.writeHead()res.setHeader() 来实现响应头部的设置。

不过需要注意,就是setHeader只能写在writeHead的前面,不然会报错。也就是说writeHead可以覆盖setHeader,但是反过来不行。

const http = require("http");
const url = require("url");

const server = http.createServer((req, res) => {
  // 设置头部,只能在writeHead的前面,不能在后面。但是writeHead可以覆盖setHeader
  res.setHeader("Content-Type", "text-plain");

  res.writeHead(200, "ok", {
    "Content-Type": "text/html",
  });
  
  res.write("hello");
  res.end("world");
});

获取响应头、删除响应头

既然可以设置响应头,当然也可以获取和删除响应头。通过getHeaderremoveHeader来获取和删除响应头。

const http = require("http");
const url = require("url");

const server = http.createServer((req, res) => {

  // 设置
  res.setHeader("Content-Type", "text-plain");
  // 获取
  console.log(res.getHeader("content-type")); //text-plain
  // 删除
  res.removeHeader("Content-Type");
  
  res.writeHead(200, "ok", {
    "Content-Type": "text/plain",
  });

  res.write("hello");
  res.end("world");
});

设置响应主体

设置响应主体主要用到 res.write() 以及 res.end() 两个方法

response.write(chunk[, encoding][, callback])

  • chunk:响应主体的内容,可以是string,也可以是buffer。当为string时,encoding参数用来指明编码方式。(默认是utf8)
  • encoding:编码方式,默认是 utf8。
  • callback:当响应体flushed时触发。

response.end([data][, encoding][, callback])

掌握了 res.write() 的话,res.end() 就很简单了。res.end() 的用处是告诉nodejs,header、body都给你了,这次响应就到这里吧。简单理解就是传递响应体并结束。

客户端

http服务除了用在服务端,还可以用在客户端。对于客户端主要用来创建http客户端请求。

创建GET请求

下面构造了个GET请求,访问 http://jsonplaceholder.typicode.com/todos/1 ,并将返回的内容打印在控制台。

const http = require("http");

const options = {
  protocol: "http:",
  hostname: "jsonplaceholder.typicode.com/todos/1",
  port: "80",
  path: "/",
  method: "GET",
};

const client = http.request(options, function (req) {
  let data = "";
  req.setEncoding("utf8");
  req.on("data", function (chunk) {
    data += chunk;
  });
  req.on("end", function () {
    console.log(data);
  });
  
  console.log(req.statusCode); // 200
  console.log(req.statusMessage); // ok
});

client.end();

输出如下,可以看到,通过get请求,获取到了返回的内容。

image.png

当然,我们还可以用便捷方法 http.get(options)

http.get("http://jsonplaceholder.typicode.com/todos/1", function (req) {
  let data = "";
  req.setEncoding("utf8");
  req.on("data", function (chunk) {
    data += chunk;
  });
  req.on("end", function () {
    console.log(data);
  });
  
  console.log(req.statusCode); // 200
  console.log(req.statusMessage); // ok
});

创建post请求

下面构造了个POST请求,访问 http://jsonplaceholder.typicode.com/posts ,并将返回的内容打印在控制台。

const options = {
  method: "POST",
  protocol: "http:",
  hostname: "jsonplaceholder.typicode.com",
  port: "80",
  path: "/posts",
  headers: {
    connection: "keep-alive",
    "content-type": "application/json; charset=UTF-8",
  },
};

// 发送给服务端的数据
const postBody = {
  title: "foo",
  body: "bar",
  userId: 1,
};

// 创建客户端请求
const client = http.request(options, function (req) {
  let data = "";
  req.on("data", function (chunk) {
    data += chunk;
  });
  req.on("end", function () {
    console.log(data);
  });
  
  console.log(req.statusCode); // 200
  console.log(req.statusMessage); // ok
});

client.write(JSON.stringify(postBody));
client.end();

输出如下,可以看到,通过post请求,获取到了返回的内容。

image.png

可以发现,服务端、客户端都有req对象,它们其实都是http.IncomingMessage实例。那这两者是一样的吗?其实是有细微差别的。具体如下图

image.png

取消请求

可以使用abort方法来终止本次请求

req.abort();

域名解析

域名解析顾名思义,就是将于域名解析为ip地址。在node中我们可以使用dns模块来实现该功能。

下面我们来说说dns模块两个个常用的方法lookupresolve4

lookup()

比如我们要查询域名 www.qq.com 对应的ip,可以通过 dns.lookup()

const dns = require("dns");

dns.lookup("www.qq.com", function (err, address, family) {
  if (err) throw err;
  console.log("ip地址为: " + address); // 101.91.22.57
});

我们知道,同一个域名,可能对应多个不同的ip。那么,如何获取一个域名对应的多个ip呢?可以这样。

const dns = require('dns');
const options = { all: true };

dns.lookup("www.qq.com", options, function (err, address, family) {
  if (err) throw err;

  console.log("ip地址为: " + JSON.stringify(address)); // [{"address":"101.91.22.57","family":4},{"address":"101.91.42.232","family":4}]
});

resolve4()

上面的例子,我们使用resolve4方法也能实现。

dns.resolve4("www.qq.com", function (err, address) {
  if (err) throw err;
  console.log(JSON.stringify(address)); // ["101.91.22.57","101.91.42.232"]
});

从上面的例子来看,两个方法都可以查询域名的ip列表。那么,它们的区别在什么地方呢?

可能最大的差异就在于,当配置了本地Host时,是否会对查询结果产生影响。

  • dns.lookup():有影响。
  • dns.resolve4():没有影响。

举例,在hosts文件里配置了如下规则。

127.0.0.1 www.qq.com

运行如下对比示例子,就可以看到区别。

const dns = require('dns');

dns.lookup('www.qq.com', function(err, address, family){
    if(err) throw err;
    console.log('配置host后,dns.lokup =>' + address);
});

dns.resolve4('www.qq.com', function(err, address, family){
    if(err) throw err;
    console.log('配置host后,dns.resolve4 =>' + address);
});

输出如下

配置host后,dns.lookup =>127.0.0.1
配置host后,dns.resolve4 =>182.254.34.74

系列文章

Node.js入门之什么是Node.js

Node.js入门之path模块

Node.js入门之fs模块

Node.js入门之url模块和querystring模块

Node.js入门之http模块和dns模块

Node.js入门之process模块、child_process模块、cluster模块

听说你还不会使用Express?

听说你还不会使用Koa?

后记

感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!

相关文章
|
2月前
|
XML 存储 网络安全
ROS入门(二):launch文件解析
该文章是关于ROS入门的第二篇教程,详细解析了ROS中的launch文件,包括其运行方式、XML格式规范、标签使用、参数替代、条件属性以及通过简单和复杂案例来演示launch文件的使用,最后介绍了如何在参数服务器上设置参数。
ROS入门(二):launch文件解析
|
2月前
|
JavaScript 数据可视化
JS如何优雅的实现模块自动滚动展示
【8月更文挑战第22天】JS如何优雅的实现模块自动滚动展示
22 1
JS如何优雅的实现模块自动滚动展示
|
1月前
Nest.js 实战 (十二):优雅地使用事件发布/订阅模块 Event Emitter
这篇文章介绍了在Nest.js构建应用时,如何通过事件/发布-订阅模式使应用程序更健壮、灵活、易于扩展,并简化服务间通信。文章主要围绕@nestjs/event-emitter模块展开,这是一个基于eventemitter2库的社区模块,提供了事件发布/订阅功能,使得实现事件驱动架构变得简单。文章还介绍了如何使用该模块,包括安装依赖、初始化模块、注册EventEmitterModule、使用装饰器简化监听等。最后总结,集成@nestjs/event-emitter模块可以提升应用程序的事件驱动能力,构建出更为松耦合、易扩展且高度灵活的系统架构,是构建现代、响应迅速且具有高度解耦特性的Nest.
|
2月前
|
JSON 前端开发 Java
【前端学java】SpringBootWeb极速入门-请求参数解析(02)
【8月更文挑战第12天】SpringBootWeb极速入门-请求参数解析(02)
17 1
【前端学java】SpringBootWeb极速入门-请求参数解析(02)
|
1月前
|
缓存 JavaScript 前端开发
JavaScript模块化开发:ES6模块与CommonJs的对比与应用
JavaScript模块化开发:ES6模块与CommonJs的对比与应用
23 2
|
2月前
|
算法 JavaScript 前端开发
国标非对称加密:RSA算法、非对称特征、js还原、jsencrypt和rsa模块解析
国标非对称加密:RSA算法、非对称特征、js还原、jsencrypt和rsa模块解析
136 1
|
2月前
|
Java Shell Linux
【Linux入门技巧】新员工必看:用Shell脚本轻松解析应用服务日志
关于如何使用Shell脚本来解析Linux系统中的应用服务日志,提供了脚本实现的详细步骤和技巧,以及一些Shell编程的技能扩展。
35 0
【Linux入门技巧】新员工必看:用Shell脚本轻松解析应用服务日志
|
2月前
|
存储 缓存 JSON
Node.js有哪些模块系统
【8月更文挑战第12天】Node.js有哪些模块系统
36 3
|
2月前
|
算法 JavaScript 前端开发
对称加密算法解析:DES、AES及其在`pycryptodome` 和 `crypto-js` 模块中的应用
对称加密算法解析:DES、AES及其在`pycryptodome` 和 `crypto-js` 模块中的应用
111 1
|
2月前
|
JavaScript 前端开发 NoSQL
使用Node.js进行后端开发入门
【8月更文挑战第10天】恭喜你完成了Node.js后端开发的入门之旅!这只是个开始,Node.js的世界远比这广阔。随着你对Node.js的深入学习和实践,你将能够构建更复杂、更强大的后端应用。不断探索、学习和实践,你将在Node.js的道路上越走越远。

相关产品

  • 云解析DNS
  • 推荐镜像

    更多