使用nodejs创建HTTP基础知识

使用Nodejs创建HTTP服务

创建HTTP服务初体验

//1. 引入HTTP模块
const http = require('http');
//2. 调用方法 创建服务对象
/**
 * request 请求报文的封装对象
 * response 响应报文的封装对象
 */
const server = http.createServer(function(request,response){
    /* 
    此方法向服务器发出信号,表明所有响应头和正文都已发送;该服务器应认为此消息已完成。 response.end() 方法必须在每个响应上调用。

如果指定了 data,则其效果类似于调用 response.write(data, encoding) 后跟 response.end(callback)。

如果指定了 callback,则将在响应流完成时调用。
    */
    response.end('Hello HTTP server');
});
//3. 监听端口
/**
 * 端口号: 计算机的服务窗口,一共有65536个窗口,也就是2^16
 * 默认端口:80 
 * 127.0.0.1 这是本机的地址
 */
server.listen(8000,function(){
    console.log("服务已经启动,端口8000监听中....");
})

局域网和云服务器上的配置

局域网

使用ipconfig查到自己的ip地址,使用ip地址加端口号一样能访问到本机开启的服务,在同一个局域网的主机能同样能访问到。

云服务器

获得请求报文中的参数

在请求的参数中包括行,头,体。

请求行和请求头

const http = require('http');
const url = require('url');//已被弃用, 使用URL类
const server = http.createServer(function (request, response) {
    // 获取报文中的内容 
    // 行中有 请求的方式    url     HTTP/1.1
    // 1. 请求的类型
    console.log(request.method);
    //2. 请求的url / 也就是url的路径内容和查询字符串
    // 也就是 /pathname?quertstring
    console.log(request.url);
    // 提取url里面的路径
    console.log(url.parse(request.url));
    console.log(url.parse(request.url).pathname);// 获取路径
    console.log(url.parse(request.url).search);// 获取路径加查询字符串
    console.log(url.parse(request.url).query);// 获取查询字符串
    console.log(url.parse(request.url,true).query);// 把查询字符串转为对象,这样皆可以获取参数了

    //3  协议的版本 
    console.log(request.httpVersion);
    console.log('Hello');
    response.end(); // 这个必须要加入,不要无法显网页,也就是客户端没有得到回应

    // 请求头信息的获取
    console.log(request.headers);
})

server.listen(80, function () {
    console.log('服务器已启动, 端口80 监听中');
})

请求体

只要POST方法才有请求体,那么这里就创建一个form表单来测试。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <form action="http://127.0.0.1" method="post">
        用户名<input type="text" name="username" id=""><br>
        密码<input type="password" name="password" id="">
        <button>登录</button>
        <!-- button 和 submit都可以 -->
    </form>
</body>
</html>
const http = require('http');
const querystring = require('querystring');// 解析请求字符串
const server = http.createServer(function (request, response) {
    // get请求,请求体是空的,只有post有请求体。
    //1. 声明字符串
    let body = '';
    //2. 绑定 data 事件
    request.on('data',(chunk) => {// 每读取一次数据,执行一次回调
        // 拼接
        body += chunk.toString();
    });
    //3. 绑定 end 事件,请求体数据读取完毕
    request.on('end',()=>{
        console.log(body);
        console.log(querystring.parse(body));
        response.end('get it ');// 应该放在这个,要不然他是同步流,还没读完就响应了
    })
})

server.listen(80, function () {
    console.log('服务器已启动, 端口80 监听中');
})

响应结果设置

code

响应头

对于响应头,我们可以做设置状态码和状态字符创

  • 状态码
	response.statusCode = 404;   // 设置状态码

image-20211103230402987

  • 响应字符串

    response.statusMessage = 'haha';
    

    image-20211103230820572

响应头

使用`response.setHeader()`
response.setHeader('Content-type','text/html;charset=utf-8');
response.setHeader('abc','1000');

image-20211103232526730

响应体

响应体不能为空,否则无法响应成功

响应体不能为空,如果没有write写入,而且end里面没有内容,那么将无法响应。

response.end()response.write()都可以写入响应体

response.write('111');
response.write('22');
response.write('33');
response.write('132');
response.end();// 响应体不能为空,如果没有write写入,而且end里面没有内容,那么将无法响应

code

 const http = require('http');
 http.createServer((request, response) => {
     // 响应行
     /* 
         响应行分为:协议版本    状态码  状态字符串
     */
     // 状态码
        response.statusCode = 404;   
    // 响应状态码
        response.statusMessage = 'haha';
     // 响应头
        response.setHeader('Content-type','text/html;charset=utf-8');
        response.setHeader('abc','1000');
     // 响应体
        response.write('111');
        response.write('22');
        response.write('33');
        response.write('132');
     response.end();// 响应体不能为空,如果没有write写入,而且end里面没有内容,那么将无法响应
 }).listen(80)

案例–背景变色

在查询字符中/?bg=rgb(x,x,x) 可以更换背景颜色

const http = require('http');
const url = require('url');
const server = http.createServer((request, response) => {
    // 中文乱码,必须设置响应头,或者是在用<meta charset = 'UTF-8'>设置,但是响应头的优先级更高
    response.setHeader('Content-Type','text/html;charset=utf-8');
    // 获取url中的bg参数
    let bg = url.parse(request.url,true).query.bg ? url.parse(request.url,true).query.bg : 'pink';
    response.end(`
    <!DOCTYPE html>
        <html lang='zh-CN'>
        <head>
        
        <style>
                body {
                 background: ${bg};
                }
             </style>
        </head>
        <body>
            <h1>
                红红火火恍恍惚惚或或或或或或或
            </h1>
        </body>
        </html>
        
    `);
});
server.listen(80, () => {
    console.log('server has started');
})

注意点:

  1. 中文必须在请求头设置字符集response.setHeader('Content-Type','text/html;charset=utf-8');,或者在用<meta charset = 'UTF-8'>设置,但是响应头的优先级更高。
  2. 使用模板字符串超级方便。

案例–根据路径返回页面

get /login 返回登录页面

get /register 返回注册页面

post /register 保存注册结果(用户名和密码)

nodejs代码:

const http = require('http');
const url = require('url');
const fs = require('fs');
const qs = require('querystring');
const server = http.createServer((request, response) => {
    // 中文乱码,必须设置响应头,或者是在用<meta charset = 'UTF-8'>设置,但是响应头的优先级更高
    response.setHeader('Content-Type','text/html;charset=utf-8');
    let method = request.method;
    let pathname = url.parse(request.url,true).pathname;
    if(method.toUpperCase() === 'GET' && pathname === '/login'){
        response.end(fs.readFileSync(__dirname + '/login.html'));// 同步读入
    }else if(method.toUpperCase() === 'GET' && pathname === '/register'){
        response.end(fs.readFileSync(__dirname + '/register.html'));// 同步读入
    }else if(method.toUpperCase() === 'POST' && pathname === '/register'){
        // 提取用户注册的信息
        let body = '';
        request.on('data',chunk=>{
            // chunk 数据块
            body+=chunk; 
        })
        // 读取结束
        request.on('end',()=>{
            // 解析用户数据为对象
            const data = qs.parse(body);
            let temp = fs.readFileSync('./user.json').toString();// 这次读取出来的是Buffer
            temp = JSON.parse(temp);// 解析为对象
            temp.data.push(data);// 向对象里面的数组压入数据
            fs.writeFileSync('./user.json',JSON.stringify(temp));
            console.log(`用户提交的内容为${body}`);
        })
        //console.log(body);// 这里是同步的,所以body是空字符串
        response.end('注册成功');
    }else{
        response.end('404 Not found');
    }
});

server.listen(80, () => {
    //console.log(__dirname);// 这个可以打印当前文件的绝对路径
    console.log('server has started');
})

user.json

{
    "data": [{
        "username": "124124",
        "pws": "123123"
    }]
}

register.html

如果表单的action不加协议头和主机名,那么它会使用当前的url。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>注册界面</title>
    <style>
        form{
           
            height: 500px;
            width: 500px;
            margin: 100px auto;
        }
    </style>
</head>
<body>
    <form action="http://127.0.0.1/register" method="post">
        <div class="container">
            <input type="text" name='username'>
            <br>
            <input type="password" name='pws'>
            <br>
            <input type="submit" value="注册">
        </div>
    </form>
</body>
</html>

服务端使用<script>标签引入js代码

html中的代码link,script ,img这种可以请求外部文件的标签也可以发送请求。只需要对路径进行一些设置即可。

不过关需要注意的是,如果加了/那么前面就需要路径,不管是.还是什么。但是若前面不加/那么就意味着当前路径。

HTML代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <!-- 这里完全可以写 /引入JavaScript代码.js-->
    <script src="http://127.0.0.1/引入JavaScript代码.js"></script>
</body>
</html>

引入的js代码

let body = document.body;
body.innerHTML = '引入成功';

nodejs代码

const http = require('http');
const url = require('url');
const fs = require('fs');
const qs = require('querystring');
const server = http.createServer((request, response) => {
    response.setHeader('Content-Type','text/html;charset=utf-8');
    let pathname = decodeURI(url.parse(request.url,true).pathname);// 解决路径中文问题
    console.log(pathname);
    if(pathname === '/引入JavaScript代码.js'){
        console.log(123);
        response.end(fs.readFileSync('./引入JavaScript代码.js'));
    }else{
        response.end(fs.readFileSync('./引入JavaScript代码.html'));
    }
});

server.listen(80, () => {
    console.log('server has started');
})

感悟

可以吧url看做服务器开启服务文件夹的目录,在它的后面加上文件的pathname,那么就可以通过服务器开启的服务来判断该响应什么文件给它。

多路径请求

像之前那个写if else判断实在是太麻烦了,而且无法写出所以的情况。

我们在项目下创建一个public文件来存放页面代码

public

  index.html

  css

  		index.css

  		app.css

  js

  		index.js

定义一个filePath

// 网站的根目录,是网站请求服务的根目录
let dirctory = __dirname + '/public';
let filePath =  dirctory + pathname; 

访问文件

fs.readFile(filePath,(err,data)=>{
	if(err){// 如果没有找到此文件
		response.statusCode = 404;
        response.end("<h1>404 Not Found</h1>");
    }else{
        response.end(data);
    }
})

服务交互总结

输入url,开始向服务请求资源,在解析为资源的时候,发现又有请求,又想服务器发送请求,得到需要的数据继续解析。如此往复可得到最终的结果。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值