【node.js】http模块笔记

165 阅读12分钟

一、创建HTTP服务端

// 1、导入http模块
const http = require('http')
// 2、创建服务对象
const server = http.createServer((request,response)=>{
    response.end('Hello HTTP Server');//设置响应体,并结束响应
})
// 3、监听端口,启动服务器
server.listen(9000,()=>{
    console.log('服务已经启动...');
})

二、HTTP服务端注意事项

  1. 命令行 ctrl+c 停止服务
  2. 当服务启动,更新代码必须重启服务才生效
  3. 响应内容中文乱码的解决办法:添加 response.setHeader('content-type',"text/html;charset=utf-8")语句
// 1、导入http模块
const http = require('http')
// 2、创建服务对象
const server = http.createServer((request,response)=>{
    // 中文出现乱码是由于字符集出现问题 :你好变成浣犲ソ
    response.setHeader('content-type',"text/html;charset=utf-8")
    response.end('你好 HTTP Server');//设置响应体,并结束响应
})
// 3、监听端口,启动服务器
server.listen(9000,()=>{
    console.log('服务已经启动...');
})
  1. 端口被占用
  2. HTTP协议默认端口是80,HTTPS协议的默认端口是443,HTTP服务开发常用端口3000,8080,8090,9000等【打开资源管理器进行端口关闭】

三、浏览器查看HTTP报文

image.png

四、获取HTTP请求报文

使用request对象

含义语法
请求方法request.method
请求版本request.httpVersion
请求路径request.url
URL路径requiret('url').parse(request.url).pathname
URL查询字符串require('url').parse(request.url,true).query
请求头request.headers
请求体request.on('data',function(chunk){}) request.on('end',function(){})

注意事项

  1. request.url只能获取路径以及查询字符串,无法获取URL中的域名以及协议的内容
  2. request.headers将请求信息转化成一个对象,并将属性名转化了小写
  3. 关于路径:如果访问网站的时候,只填写了IP地址或者域名信息,此时请求的路径为“/”
  4. 关于favicon.ico:这个请求是属于浏览器自动发生的请求
// 1、导入http模块
const http = require('http')
// 2、创建服务对象
const server = http.createServer((request,response)=>{
    // 1、获取请求方法
    console.log(request.method);
    //GET
    //GET
    // 2、获取请求的url,只包含url中的路径与查询字符串
    console.log(request.url); 
    // /
    // 3、获取http协议的版本号
    console.log(request.httpVersion);
    // 1.1
    // 4、获取http的请求头
    console.log(request.headers);
    // {
    //     host: '127.0.0.1:9000',
    //     'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0',
    //     accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8',
    //     'accept-language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    //     'accept-encoding': 'gzip, deflate, br',
    //     dnt: '1',
    //     connection: 'keep-alive',
    //     cookie: 'Hm_lvt_d7c7037093938390bc160fc28becc542=1696589624',
    //     'upgrade-insecure-requests': '1',
    //     'sec-fetch-dest': 'document',
    //     'sec-fetch-mode': 'navigate',
    //     'sec-fetch-site': 'none',
    //     'sec-fetch-user': '?1'
    //   }
    // 5、获取http请求头里的某个键值
    console.log(request.headers.host);
    // 127.0.0.1:9000
    response.end('Server');//设置响应体,并结束响应
})
// 3、监听端口,启动服务器
server.listen(9000,()=>{
    console.log('服务已经启动...');
})

五、获取请求体

<body>
    <form action="http:127.0.0.1:9000" method="post">
        <input type="text" name="name">
        <input type="text" name="age">
        <button type="submit">提交</button>
    </form>
</body>
const http = require('http')
const server = http.createServer((request,response)=>{
    response.setHeader('content-type','text/html;charset=utf-8')
    // 1、声明一个变量
    let body = '';
    // 2、绑定data事件
    request.on('data',chunk=>{
        body+=chunk
    })
    // 3、绑定end事件
    request.on('end',()=>{
        console.log(body);
        // name=yt&age=111
        // 4、设置响应
        response.end('Hello HTTP')
    })
})
server.listen(9000,()=>{
    console.log("服务器已启动...");
});

六、获取请求路径与查询字符串

方式一:导入url模块

  1. 解析url:url.parse(request.url,true)
  2. 获取url:url.parse(request.url,true).pathname
  3. 查询指定参数【注意:url.parse(request.url,true)中要加入true】:url.parse(request.url,true).query.name
// 导入http模块
const http = require('http');
// 导入url模块
const url = require('url');
// 创建服务器对象
const server = http.createServer((request,response)=>{
    // 当我路径输入 http://127.0.0.1:9000/?name=yt&age=14
    console.log(request.url);
    // /?name=yt&age=14
    // /favicon.ico
    // 解析路径参数(解析request.url)[true是为了更好的解析url拼接的参数]
    let res = url.parse(request.url,true)
    console.log(res);
    // Url {
    //     protocol: null,
    //     slashes: null,
    //     auth: null,
    //     host: null,
    //     port: null,
    //     hostname: null,
    //     hash: null,
    //     search: '?name=yt&age=14',
    //     query: 'name=yt&age=14',
    //     pathname: '/',
    //     path: '/?name=yt&age=14',
    //     href: '/?name=yt&age=14'
    //   }

    // 获取url
    let pathname = res.pathname
    console.log(pathname);
    // /
    // 查询字符串
    let name = res.query.name
    console.log(name);
    response.end('url')
})
// 监听端口,启动服务器
server.listen(9000,()=>{
    console.log("服务器已启动");
})

方式二:实例化URL对象

  1. 解析url: new URL(request.url,"http://127.0.0.1")
  2. 获取url:new URL(request.url,"http://127.0.0.1").pathname
  3. 查询指定参数【注意:searchParams获取参数要使用get方法】:new URL(request.url,"http://127.0.0.1").searchParams.get('name')
// 导入http模块
const http = require('http');

// 创建服务器对象
const server = http.createServer((request,response)=>{
    // 当我路径输入 http://127.0.0.1:9000/?name=yt
    let url = new URL(request.url,"http://127.0.0.1")
    console.log(url);
    // URL {
    //     href: 'http://127.0.0.1/?name=yt',
    //     origin: 'http://127.0.0.1',
    //     protocol: 'http:',
    //     username: '',
    //     password: '',
    //     host: '127.0.0.1',
    //     hostname: '127.0.0.1',
    //     port: '',
    //     pathname: '/',
    //     search: '?name=yt',
    //     searchParams: URLSearchParams { 'name' => 'yt' },
    //     hash: ''
    //   }
    console.log(url.pathname);
    // /
    // 获取指定参数
    console.log(url.searchParams.get('name'));
    // yt
    response.end('url')
})
// 监听端口,启动服务器
server.listen(9000,()=>{
    console.log("服务器已启动");
})

七、实现指定路径和方法进入(登录和注册为例)

// 1、导入http模块
let http = require('http');
// 2、创建服务对象
const server = http.createServer((request,response)=>{
    // 解决中文乱码问题
    response.setHeader("content-type",'text/html;charset=utf-8')
    // 获取请求方法
    let {method} = request;
    // 获取请求的url路径
    let {pathname} = new URL(request.url,'http://127.0.0.1')
    // console.log(method);
    // console.log(pathname);
    // GET
    // /login/
    // GET
    // /favicon.ico
    // 判断
    if(method === 'GET' && pathname === '/login')
    {
        // 登录的情形
        response.end('登录页面')
    }else if(method === 'GET' && pathname === '/register'){
        // 注册情形
        response.end('注册界面')
    }else{
        response.end('Not Found')
    }
    response.end('practice');
});

// 3、监听端口 启动服务
server.listen(9000,()=>{
    console.log("服务器已经启动");
})

八、设置HTTP的响应报文

// 1、导入http模块
let http = require('http');
// 2、创建服务对象
const server = http.createServer((request,response)=>{
    // 1、设置响应状态码
    request.statusCode = 200;
    // 2、设置响应描述
    request.statusMessage = "requestDescribe";
    // 3、设置响应头(可以设置自定义的响应头)
    response.setHeader('content-type','text/html;charset=utf-8')
    // 4、设置多个同名的响应头
    response.setHeader('similar',[1,2,3])
    // 5、设置响应体:response.write(可以多次调用
    //(如果设置response.write(),一般不会在设置response.end()里的内容)
    response.write("xyt")
    response.end('practice');
});
// 3、监听端口 启动服务
server.listen(9000,()=>{
    console.log("服务器已经启动");
})

image.png

案例1:响应文件内容为html、css、js的文件(麻烦)

// 1、导入http模块
let http = require("http");
// 2、创建服务器对象
const server = http.createServer((request, response) => {
  response.end(`<!DOCTYPE html>
  <html lang="en">
  <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <title>Document</title>
      <style>
      td{
        background-color:red;
      }
      </style>
  </head>
  <body>
  <table border="1"><tr><td>test</td></tr></table>
  </body>
  <script>
    
  </script>
  
  </html>`); //设置响应
});
// 监听端口,启动服务器
server.listen(9000, () => {
  console.log("服务器已经启动......");
});

案例2:响应文件内容为html、css、js的文件(解决案例1的麻烦问题,更新页面方便,响应方便) 第一步:创建html文件

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        td {
            background-color: red;
        }
    </style>
</head>
<body>
    <table border="1">
        <tr>
            <td>test</td>
        </tr>
    </table>
</body>
<script>

</script>

</html>

第二步:导入html文件

// 1、导入http模块
let http = require("http");
// 2、导入fs模块
let fs = require("fs");
// 3、创建服务器对象
const server = http.createServer((request, response) => {
    // 读取文件的内容
    let html=fs.readFileSync('./http.html')
  //设置响应end()可以传的参数类型为字符串或者buffer
  response.end(html);
});
// 监听端口,启动服务器
server.listen(9000, () => {
  console.log("服务器已经启动......");
});

九、网页资源的加载的基本的过程

浏览器并发获取请求 html -> css -> img -> js

十、实现网页引入外部资源(麻烦)

// 1、导入http模块
let http = require("http");
// 2、导入fs模块
let fs = require("fs");
// 3、创建服务器对象
const server = http.createServer((request, response) => {
  //获取请求的url的路径
  let { pathname } = new URL(request.url,'http://127.0.0.1');
  if (pathname === "/") {
    // 读取html文件的内容
    let html = fs.readFileSync(__dirname, "./http.html");
    //设置响应end()可以传的参数类型为字符串或者buffer
    response.end(html);
  } else if (pathname === "./http.css") {
    // 读取css文件的内容
    let css = fs.readFileSync(__dirname, "./http.css");
    //设置响应end()可以传的参数类型为字符串或者buffer
    response.end(css);
  } else if (pathname === "./http.js") {
    // 读取css文件的内容
    let js = fs.readFileSync(__dirname, "./http.js");
    //设置响应end()可以传的参数类型为字符串或者buffer
    response.end(js);
  }else{
    response.statusCode = 404
    response.end('<h1>404 Not Found</h1>');
  }
});
// 监听端口,启动服务器
server.listen(9000, () => {
  console.log("服务器已经启动......");
});

十一、静态资源与动态资源

静态资源:内容长时间不发生改变的资源。【图片、视频、css文件、JS文件、HTML文件、字体文件】 动态资源:内容经常更新的资源。【百度首页、网页首页、京东搜索列表页面等】

十二、搭建静态资源服务

// 1、导入http模块
let http = require("http");
// 2、导入fs模块
let fs = require("fs");
// 3、创建服务器对象
const server = http.createServer((request, response) => {
  //获取请求的url的路径
  let { pathname } = new URL(request.url,'http://127.0.0.1');
  // 拼接文件路径
  let filePath = __dirname+'/page'+pathname;
  // 读取文件fs异步API
  fs.readFile(filePath,(err,data)=>{
    if (err) {
      response.statusCode = 500;
      response.end('文件读取失败');
      return;
    }
    // 响应文件内容
    response.end(data);
  })
  
});
// 监听端口,启动服务器
server.listen(9000, () => {
  console.log("服务器已经启动......");
});

十三、静态资源目录与网站根目录

HTTP服务在哪个文件夹中寻找静态资源,那个文件夹就是静态资源目录(网站根目录)。

// 1、导入http模块
let http = require("http");
// 2、导入fs模块
let fs = require("fs");
// 3、创建服务器对象
const server = http.createServer((request, response) => {
  //获取请求的url的路径
  let { pathname } = new URL(request.url,'http://127.0.0.1');
  // 声明一个变量,存储网站的根目录
  let root = __dirname + '/page';
  // 拼接文件路径
  let filePath = root + pathname;
  // 读取文件fs异步API
  fs.readFile(filePath,(err,data)=>{
    if (err) {
      response.setHeader('content-type','text/html;charset=utf-8')
      response.statusCode = 500;
      response.end('文件读取失败');
      return;
    }
    // 响应文件内容
    response.end(data);
  })
  
});
// 监听端口,启动服务器
server.listen(9000, () => {
  console.log("服务器已经启动......");
});

十四、网站中的URL

网页中的URL主要分为两大类:相对路径与绝对路径

1、绝对路径

绝对路径可靠性强,而且相对容易理解,在项目中运用较多

形式特点
atguihu.com/web直接向目标资源发送请求,容易理解。网站的外链会用到此形式
//atguihu.com/web与页面URL的协议拼接形成完整的URL再发生请求。大型网站用的比较多(方便更改域名或IP地址)
/web与页面URL的协议、主机名、端口拼接形成完整URL再发送请求。中小型网站

2、相对路径

相对路径在发送请求时,需要与当前页面URL路径进行计算,得到完整URL后,再发生请求,学习阶段用的较多。 相对路径不可靠,它是以当前路径为准,当前路径出现问题可能会导致请求不到资源。 例如当前网页URL为 www.atguihu.com/course/h5.h…

形式最终的URL
./css/app.csswww.atguihu.com/course/css/…
js/app.jswww.atguihu.com/course/js/a…
../img/log.pngwww.atguihu.com/course/img/…
../../mp4/show.mp4www.atguihu.com/mp4/show.mp…

3、网页URL的使用场景

a标签的href link标签href script标签src img标签src video audio 标签src form中的action AJAX请求中的URL

十五、设置MIME类型(资源类型)

媒体类型(通常称为Multipurpose Internet Mail Extensions 或MIME类型)是一种标准,用来表示文档、文件或字节流的性质和格式

mime类型结构:【type】/【subType】

例如:text/html text/css image/jpg image/png application/json

HTTP服务可以设置响应头Content-Type来表明响应体的MIME类型,浏览器会根据该类型决定如何处理资源

以下是常见文件对应的mime类型 html:'text/html' css:'text/css' js:'text/javascript' png:'image/png' jpg:'image/jpeg' gif:'image/gif' mp4:'video/mp4' json:'application/json' 对于未知的资源类型,可以选择applicstion/octet-stream类型,浏览器在遇到该类型的响应时,会对响应体内容进行独立存储,也就是我们常见的下载效果。

// 1、导入http模块
const http = require("http");
// 2、导入fs模块
const fs = require("fs");
const path = require("path");
// 声明一个变量
let mime = {
  html: "text/html",
  css: "text/css",
  js: "text/javascript",
  png: "image/png",
  jpg: "image/jpeg",
  gif: "image/gif",
  mp4: "video/mp4",
  json: "application/json",
};
// 3、创建服务器对象
const server = http.createServer((request, response) => {
  //获取请求的url的路径
  let { pathname } = new URL(request.url, "http://127.0.0.1");
  // 声明一个变量,存储网站的根目录
  let root = __dirname + "/page";
  // 拼接文件路径
  let filePath = root + pathname;
  // 读取文件fs异步API
  fs.readFile(filePath, (err, data) => {
    if (err) {
      response.setHeader("content-type", "text/html;charset=utf-8");
      response.statusCode = 500;
      response.end("文件读取失败");
      return;
    }
    // 获取文件的后缀名
    let ext = path.extname(filePath).slice(1);
    // 获取对应的类型
    let type = mime[ext]
    if (type) {
      // 匹配到了
      //解决乱码问题charset=utf-8的优先级高于html里的meta
      // response.setHeader('content-type',type+';charset=utf-8');
      if(ext === 'html')
      {
        response.setHeader('content-type',type+';charset=utf-8');
      }else{
        response.setHeader('content-type',type);
      }
    }else{
      // 没有匹配到
      response.setHeader('content-type','application/octet-stream');
    }
    // content-type的内容不能写死,可能会出现请求类型混乱
    // response.setHeader('content-type','dd')
    // 响应文件内容
    response.end(data);
  });
});
// 监听端口,启动服务器
server.listen(9000, () => {
  console.log("服务器已经启动......");
});

十六、完善错误请求

// 1、导入http模块
const http = require("http");
// 2、导入fs模块
const fs = require("fs");
const path = require("path");
// 声明一个变量
let mime = {
  html: "text/html",
  css: "text/css",
  js: "text/javascript",
  png: "image/png",
  jpg: "image/jpeg",
  gif: "image/gif",
  mp4: "video/mp4",
  json: "application/json",
};
// 3、创建服务器对象
const server = http.createServer((request, response) => {
  if (request.method !== 'GET') {
    response.statusCode = 405;
    response.end('<h1>405 Not Allowed</h1>');
    return;
  }
  //获取请求的url的路径
  let { pathname } = new URL(request.url, "http://127.0.0.1");
  // 声明一个变量,存储网站的根目录
  let root = __dirname + "/page";
  // 拼接文件路径
  let filePath = root + pathname;
  // 读取文件fs异步API
  fs.readFile(filePath, (err, data) => {
    if (err) {
      //设置字符集
      response.setHeader("content-type", "text/html;charset=utf-8");
      // 判断错误的代号
      switch (err.code) {
        case "ENOENT":
          response.statusCode = 404;
          response.end("<h1>404 Not Found</h1>");
        case 'EPERM':
          response.statusCode = 403;
          response.end("<h1>403 Not Found</h1>");
        default:
          response.statusCode = 500;
          response.end("<h1>Internal Server Error</h1>");
      }
      return;
    }
    // 获取文件的后缀名
    let ext = path.extname(filePath).slice(1);
    // 获取对应的类型
    let type = mime[ext];
    if (type) {
      // 匹配到了
      //解决乱码问题charset=utf-8的优先级高于html里的meta
      // response.setHeader('content-type',type+';charset=utf-8');
      if (ext === "html") {
        response.setHeader("content-type", type + ";charset=utf-8");
      } else {
        response.setHeader("content-type", type);
      }
    } else {
      // 没有匹配到
      response.setHeader("content-type", "application/octet-stream");
    }
    // content-type的内容不能写死,可能会出现请求类型混乱
    // response.setHeader('content-type','dd')
    // 响应文件内容
    response.end(data);
  });
});
// 监听端口,启动服务器
server.listen(9000, () => {
  console.log("服务器已经启动......");
});

十七、GET和POST场景与区别

1、场景

GET:

  1. 在地址栏直接输入url访问
  2. 点击a链接
  3. link标签引入css
  4. script标签引入js
  5. video与audio引入多媒体
  6. img标签引入图片
  7. form标签中的method为get(不区分大小写)
  8. ajax中的get请求 POST
  9. form标签中的method为post(不区分大小写)
  10. AJAX的post请求

十八、GET和POST请求的区别

GET和POST是HTTP协议请求的两种方式,主要有如下几个区别

  1. 作用:GET请求数据,POST提交数据。
  2. 参数位置:GET带参数请求是将参数拼接到URL之后,POST带参数请求是将参数放在请求体中。
  3. 安全性:POST请求(可抓包)相对GET安全,因为GET的请求会暴露在地址栏上。
  4. 大小限制:GET请求大小有限制,一般为2K,而POST请求则没有大小的限制。