HTTP模块(用Node.js创建web服务器)

497 阅读6分钟

app.js

自动生成:

安装node snippets插件,输node-http-server

var http = require('http');
http.createServer((request, response)=> {
  //设置响应头
  response.writeHead(200, {'Content-Type''text/plain'});
  //输出并结束响应
  response.end('Hello World');
}).listen(8081);  //监听端口

console.log('Server running at http://127.0.0.1:8081/');

手动输入

const http = require('http');// 引用创建网站服务器的模块
const url = require('url');// 用于处理url地址
const app = http.createServer();// 创建web服务器(app就是网站服务器对象)

// 当客户端有请求来,请求在服务器端通过事件来触发
app.on('request', (req, res) => {  //请求的事件名称,事件处理函数(请求对象,响应对象)
	
	if (req.method == 'POST') {  // 获取请求方式 req.method,根据不同的请求方式做不同的响应
		res.end('post') 
	} else if (req.method == 'GET') {
		res.end('get') 
	}	

	// 获取请求地址 req.url, 根据不同的请求地址,返回不同内容
	// if (req.url == '/index' || req.url == '/') {
	// 若没有写请求地址(访问 localhost:3000),此时req.url是一个'/'(要默认访问首页,加上|| req.url == '/')	
	// 	res.end('<h2>欢迎来到首页</h2>');  打印响应内容(是代码)
	// }else { //请求的地址不存在
	// 	res.end('not found');
	// }
	
	// 获取请求头 req.headers
	// console.log(req.headers['accept']); 获取到其中具体某一项
        
        //设置响应头:状态码、内容类型(html)、字符集
	res.writeHead(200, {
		'content-type': 'text/html;charset=utf8'  //响应体里有中文
	});
        
        res.write('this');
        
        //parse被弃用?
	// 1) 要解析的url地址
	// 2) 将查询参数解析成对象形式
	//let { query, pathname } = url.parse(req.url, true);
	//console.log(query.name)
	//console.log(query.age)
	//根据浏览器不同的请求地址,返回不同的响应体
	//if (pathname == '/index' || pathname == '/') {
	//	res.end('<h2>欢迎来到首页</h2>');//除非把content-type改成text/html,否则不解析
	//}else if (pathname == '/list') {
	//	res.end('welcome to listpage'); //此响应体是纯文本类型
	//}else { //请求的地址不存在
	//	res.end('not found');  //res.end(); 结束响应,必须得写
	//}
        
        //新的?
        const myURL=new URL(req.url,'http://localhost:3000/');

	// res.end('<h2>hello user</h2>');
});
// 监听端口(否则无法向外界提供服务)
app.listen(3000);
console.log('网站服务器启动成功');

创建了网站服务器必须监听端口,才能向外界提供服务

执行: nodemon 文件名.js

访问:在本地电脑启动的该服务器,用域名localhost:3000

HTTP协议

超文本传输协议,是客户端(用户)和服务器端(网站)请求和应答的标准,规范了请求报文和响应报文

在HTTP请求和响应的过程中传递的数据块就叫报文,包括要传送的数据和一些附加信息,并且要遵守规定好的格式。

2021-11-08.png

请求报文

HTTP请求报文由三部分组成:请求行,请求头、空行 / 请求正文

  • 请求行:请求类型(GET/POST/PUT...) URL路径 HTTP协议的版本

  • 请求头:键值对格式,描述客户端请求哪台主机及其端口,以及客户端的一些环境信息等

  • 空行:空行就是\r\n (POST请求时候有?必须有?)

  • 请求正文:当使用POST等方法时,通常需要客户端向服务器传递数据。这些数据就储存在请求正文中(GET方式是保存在url地址后面,不会放到这里,相应的请求体是空的)

行      POST  /s?ie=utf-8  HTTP/1.1 
头      Host: ![]()atguigu.com
        Cookie: name=guigu
        Content-type: application/x-www-form-urlencoded 告知服务器请求体是什么类型的
        User-Agent: chrome 83

体      username=admin&password=admin

1. 请求方式(Request Method)

告诉服务器端当前请求要做的事件类型

GET:请求数据(如刷新、跳转地址、浏览器自动发送的图标请求)

POST:发送数据(如登录操作、表单),POST相对GET更安全

2. 请求地址(Request URL)

 app.on('request', (req, res) => {
     req.method   // 获取请求方法
     req.url      // 获取请求地址
     req.headers  // 获取请求报文
 });

访问: localhost:3000/index(/index是请求地址)

3. 请求参数

客户端向服务器端发送请求时,有时需要携带一些客户信息,客户信息需要通过请求参数的形式传递到服务器端,比如登录操作。

GET请求参数
  • 参数被放在浏览器地址栏中,如http://localhost:3000/index?name=zhangsan&age=20 ?name=zhangsan&age=20 (?后表示携带的参数,用=分割的键值对,传递多个参数用&连接)
  • 参数获取需要借助系统模块url,url模块用来处理url地址const url = require('url');console.log(req.url)打印:/index?name=zhangsan&age=20
POST请求参数
  • 参数被放置在请求体中进行传输(在Network的Form Data里查看)
  • POST参数是通过事件的方式接收的,需要使用data事件和end事件,分多次接收
  • 使用querystring系统模块将参数转换为对象格式

先开启服务器端:nodemon 文件名.js

const http = require('http');
const app = http.createServer();
const querystring = require('querystring');// 处理请求参数模块
app.on('request', (req, res) => {
	let postParams = '';  //用于存储POST参数
        //参数1:事件名称 参数2:事件处理函数
	req.on('data', params => {  //当请求参数传递的时候触发data事件
		postParams += params;  //分多次接收当前传递过来的POST参数
	});
	req.on('end', () => {  //当参数传递完成的时候触发end事件
		console.log(querystring.parse(postParams)); //把字符串转换为对象,querystring被弃用,下载npm install query-string ?
                //postParams是username=xxx&password=xxx
	});
	res.end('ok'); //对每次请求,服务器端都要响应结束,否则客户端一直处于等待状态
});
app.listen(3000);// 监听端口
console.log('网站服务器启动成功');

在客户端访问:

<body>
	<!--
		method: 指定当前表单提交的方式,可以是GET或POST,不写默认是GET
		action: 指定当前表单提交的地址,这里用已经开启的自己的服务器
	-->
	<form method="post" action="http://localhost:3000">
		<input type="text" name="username">
		<input type="password" name="password">
		<input type="submit">
	</form>
	<!-- 发现在表单POST请求类型后有GET请求,因为点击表单按钮发送POST请求后
	表单发送了跳转页面的默认行为,跳转行为默认是GET类型 -->
</body>

响应报文

  • 响应头:响应头用于描述服务器的基本信息,以及客户端如何处理数据

  • 空格:CRLF(即 \r\n)分割

  • 消息体:服务器返回给客户端的数据

响应行  HTTP协议的版本 响应状态码 响应状态字符串 响应头  键值对格式,对响应体内容做相关的描述(如类型是什么?长度是多少?压缩方式是哪种?...) 空行必须有 响应体是主要的返回结果,html内容放在响应的报文当中来传输。

行      HTTP/1.1  200  OK
头      Content-Type: text/html;charset=utf-8
        Content-length: 2048
        Content-encoding: gzip
空行    
体      <html>
            <head>
            </head>
            <body>
                <h1>尚硅谷</h1>
            </body>
        </html>

1. 常用的响应状态码

  1. 在Network里查看状态码:Status
  • 200 请求成功
  • 401 未授权
  • 403 被禁止
  • 404 请求的资源没有被找到
  • 500 服务器端错误
  • 400 客户端请求有语法错误(如请求路径错了/请求参数不匹配)
  1. 为客户端设置不同的状态码
  • 设置响应头:res.writeHead()的第一个参数

2. 内容类型 Content-Type

指定响应返回的是什么内容类型:

res.writeHead()的第二个参数,该参数是个对象,存储响应头的信息

  • text/html 返回的是html文件
  • text/css 返回的是css文件
  • application/javascript 返回的是js文件
  • image/jpeg
  • application/json
 app.on('request', (req, res) => {
     res.writeHead(200, {  // 设置响应报文(不写状态码默认是200)
     'Content-Type': 'text/plain;charset=utf8'  //返回的响应体是纯文本
     });
 });