Node.js开发HTTP服务端

961 阅读7分钟

一、创建一个简单的HTTP服务器

  • 第一步:导入http模块。
  • 第二步:创建服务对象,createServer()方法的参数是回调函数,回调函数有两个参数,分别是request和response对象。
  • 第三步:启动http服务,listen()方法的第一个参数是端口号,第二个参数是回调函数,当服务启动时,执行回调函数。

示例:

const http = require('http');

//创建服务对象
const server = http.createServer((request,response)=>{
    //当服务接收到http请求后执行回调函数
    response.end('Hello HTTP Server'); //设置响应体,并返回响应内容
});

//监听端口,启动服务器
server.listen(9000,()=>{
    //服务启动成功后执行回调函数
    console.log('服务启动成功');
});

注意事项:

  • 使用Ctrl + c停止服务
  • 中文乱码的解决方法
response.setHeader('content-type','text/html;charset=utf-8'); //设置响应头
  • 端口被占用的解决方法:杀死占用端口的进程或者换一个端口号
  • HTTP的默认端口是80

二、HTTP请求

1、获取请求行和请求头

服务端代码

const server = http.createServer((request,response)=>{
    console.log(request);
});

获取请求的方法

request.method

获取请求的URL

request.url

获取请求头

requrest.headers

请求头的内容如下

{
  host: 'localhost:9000',  
  connection: 'keep-alive',
  'cache-control': 'max-age=0',
  'sec-ch-ua': '"Not.A/Brand";v="8", "Chromium";v="114", "Google Chrome";v="114"',
  'sec-ch-ua-mobile': '?0',
  'sec-ch-ua-platform': '"Windows"',
  'upgrade-insecure-requests': '1',
  'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
  accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
  'sec-fetch-site': 'none',
  'sec-fetch-mode': 'navigate',
  'sec-fetch-user': '?1',
  'sec-fetch-dest': 'document',
  'accept-encoding': 'gzip, deflate, br',
  'accept-language': 'zh-CN,zh;q=0.9',
  cookie: 'Idea-8525aa25f9=d3805295-ca45-4555-9a3f-37900fb1ec59'
}

2、获取请求体

创建一个 HTTP 服务器,并在 request 对象上监听 data 和 end 事件。当浏览器发送请求时,将请求体分块发送。在每个分块被接收时,都会触发一次data事件,需要将其转换为字符串并将其附加到 body 变量中。当请求体接受完毕后, end 事件被触发,此时打印出请求体,并向浏览器发送响应。

const http = require('http');

const server = http.createServer((request,response)=>{
    //当服务接收到http请求后执行回调函数
    response.setHeader('content-type','text/html;charset=utf-8'); //设置响应头
    
    let body = '';
    
    request.on('data',chunk=>{
        body += chunk.toString();
    });
    
    request.on('end',()=>{
        console.log(body);
        response.end('Hello HTTP Server'); //设置响应体,并返回响应内容
    });
});

//监听端口,启动服务器
server.listen(9000,()=>{
    //服务启动成功后执行回调函数
    console.log('服务启动成功');
});

3、获取请求路径和请求参数

(1)方式一:

请求URL:http://localhost:9000/search?param=hello 使用url模块解析请求路径和参数

const url = require('url');

1.解析前的URL

console.log(request.url);

结果是"请求路径 + 请求参数"

/search?param=hello

2.解析request.urlurl.parse()不传第二个参数

let res = url.parse(request.url); //解析URL
console.log(res);

解析后的res对象,请求路径是pathname属性,请求参数query属性被解析成字符串。

Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: '?param=hello',
  query: 'param=hello',
  pathname: '/search',
  path: '/?param=hello',
  href: '/?param=hello'
}

注意:请求参数query属性是一个字符串

3.解析request.urlurl.parse()的第二个参数是true

let res = url.parse(request.url,true); //获取请求路径,第二个参数为true表示解析请求参数

解析后的res对象,请求参数被解析成对象

Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: '?param=hello',
  query: [Object: null prototype] { param: 'hello' },
  pathname: '/search',
  path: '/?param=hello',
  href: '/?param=hello'
}

注意:请求参数query属性是一个对象,请求参数被拆成了键值对的形式

4.完整示例

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

const server = http.createServer((request,response)=>{
    let res = url.parse(request.url,true); //获取请求路径,第二个参数为true表示解析请求参数
    
    let pathname = res.pathname; //请求路径
    let param = res.query.param; //请求参数

    console.log(pathname,param);
    
    //当服务接收到http请求后执行回调函数
    response.setHeader('content-type','text/html;charset=utf-8'); //设置响应头
    response.end('Hello HTTP Server'); //设置响应体,并返回响应内容
});

//监听端口,启动服务器
server.listen(9000,()=>{
    //服务启动成功后执行回调函数
    console.log('服务启动成功');
});

请求http://localhost:9000/search?param=hello的执行结果

/search hello

(2)方式二(推荐使用):

使用URL对象解析请求路径

//第一个参数是请求路径和参数,第二个参数是请求的IP和端口
let url = new URL(request.url,'http://localhost:9000'); 

console.log(url);

打印结果

URL {
  href: 'http://localhost:9000/search?param=hello',
  origin: 'http://localhost:9000',
  protocol: 'http:',
  username: '',
  password: '',
  host: 'localhost:9000',
  hostname: 'localhost',
  port: '9000',
  pathname: '/search',
  search: '?param=hello',
  searchParams: URLSearchParams { 'param' => 'hello' },
  hash: ''
}

注:pathname属性是请求路径,searchParams属性是请求参数

完整实例

const http = require('http');

const server = http.createServer((request,response)=>{
    let url = new URL(request.url,'http://localhost:9000');
    
    console.log(url.pathname);
    
    //使用get方法获取请求参数的value,参数是key
    console.log(url.searchParams.get('param'));

    //当服务接收到http请求后执行回调函数
    response.setHeader('content-type','text/html;charset=utf-8'); //设置响应头
    response.end('Hello HTTP Server'); //设置响应体,并返回响应内容
});

//监听端口,启动服务器
server.listen(9000,()=>{
    //服务启动成功后执行回调函数
    console.log('服务启动成功');
});

访问http://localhost:9000/search?param=hello的执行结果

/search
hello

三、HTTP响应

1、设置响应行和响应头

(1)设置响应状态码和状态描述

const http = require('http');

const server = http.createServer((request,response)=>{
    //当服务接收到http请求后执行回调函数
    response.statusCode = 202;  //设置响应状态码
	response.statusMessage = 'hello,world!'; //设置响应状态描述
    response.end('Hello HTTP Server'); //设置响应体,并返回响应内容
}); 

//监听端口,启动服务器
server.listen(9000,()=>{
    //服务启动成功后执行回调函数
    console.log('服务启动成功');
});

image.png

(2)设置响应头

使用response.setHeader(key,value)方法,第一个参数是响应头名称,第二个参数是响应头的值

response.setHeader('content-type','text/html;charset=utf-8'); //设置响应头
response.setHeader('Server','Node.js'); //设置服务器名称
response.setHeader('Customer-Header','hello,world!'); //设置自定义响应头

image.png

(3)设置多个响应头

response.setHeader('multiple-header',['first-header','second-header','third-header']);

image.png

2、设置响应体

(1)使用response.write(内容);设置响应体

response.write('hello,');
response.write('world!\n');
response.end();

页面显示“hello,world!”

(2)使用response.end(内容);设置响应体

response.end()方法会在设置响应体之后,将响应返回给浏览器。

response.end('Hello HTTP Server'); //设置响应体,并返回响应内容

页面显示“Hello HTTP Server”

3、静态资源

(1)获取静态资源

如果一个HTML页面引用了静态资源,则浏览器会发送多个请求,每个请求都会获取一个静态资源,例如:css、javascript、图片等。

image.png

浏览器发送的请求

image.png

(2)处理静态资源请求

因为每个静态资源都对应一个请求路径(http://localhost:9000/请求路径/静态资源名称),因此需要对静态资源请求进行处理,当请求到达时,读取对应的静态资源文件,然后将静态资源的内容返回给浏览器。

(3)编写一个静态资源服务

为了演示静态资源请求和普通的请求一样,下面的代码直接将请求路径写死在程序中,在实际开发中不应该这样写。

目录结构

image.png

index.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>
    <link rel="stylesheet" href="./index.css">
</head>
<body>
    <table border="1">
        <tr>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td></td>
            <td></td>
            <td></td>
        </tr>
    </table>
    <script src="./index.js"></script>
</body>
</html>

index.css

td {
    padding: 20px 40px;
}

table tr:nth-child(odd){
    background: #aef;
}

table tr:nth-child(even){
    background: #fcb;
}

table,td{
    border-collapse: collapse;
}

index.js

let tds = document.querySelectorAll('td');

tds.forEach(item => {
    item.onclick = function(){
        this.style.background = '#222';
    }
});

10_响应练习.js

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

const server = http.createServer((requrest,response)=>{
    //获取请求URL的路径
    let {pathname} = new URL(requrest.url,'http://localhost:9000');
    if(pathname === '/'){
        let html = fs.readFileSync(__dirname + '/index.html');
        response.end(html); //end方法的参数可以是字符串,也可以是buffer
    }else if(pathname === '/index.css'){
        let css = fs.readFileSync(__dirname + '/index.css');
        response.end(css);
    }else if(pathname === '/index.js'){
        let js = fs.readFileSync(__dirname + '/index.js');
        response.end(js);
    }else{
        response.statusCode = 404;
        response.end('<h1>404 Not Found</h1>');
    }
});

server.listen(9000,()=>{
    console.log('服务已启动......');
});