当前位置: 首页 > Web前端 > JavaScript

前端呃,什么时候,你要写一个HTTP服务器?

时间:2023-03-27 16:40:37 JavaScript

前面呃,什么时候,你要写一个HTTP服务器?刚开始接触工程项目的时候,看到项目控制台正在building,过一会突然弹出一个url地址。点开一看,竟然是刚才写的网页,太神奇了。当你连接到后端小伙伴的接口时,你带了数据,接口却给你返回了500错误;你去后端,后端说传不上去,你也不知道为什么传不上去,反正按他说的改就完了,返回200成功。有的时候你的请求莫名其妙的跨域,后台说让你自己处理,你就自己去找解决办法。但是为什么要跨域呢?您不知道后端是如何配置的。终于有一天,您从痛苦中吸取教训并决定改变您的过去。一定要自己架设HTTP服务器,一波三折彻底讲清楚,拒绝上当,拒绝做只听命令的领导。但话虽如此,如何开始?别担心,一切都为你准备好了。编写HTTP服务器需要后端语言,自然首选Node.js。接下来我们将基于Node.js的http模块搭建一个HTTP服务器。http模块一个超级简单的HTTPWeb服务器的例子:consthttp=require('http')constserver=http.createServer((request,response)=>{response.statusCode=200response.end('helloworld')})server.listen(3000)这里引入http模块,提供createServer方法,传入回调函数创建服务器。现在将代码写入index.js,运行起来超级简单:$nodeindex.js打开浏览器,输入http://localhost:3000,就可以看到网页上显示的helloworld。代码分析http.createServer方法的参数是一个回调函数,这个回调函数有两个参数——它们是HTTP服务器的核心。第一个参数是request对象request,第二个参数是response对象response。您可以将它们视为两个包,一个包含与请求相关的数据,一个包含与响应相关的操作。request里面包含了详细的请求数据,也就是我们前端接口传过来的数据。通过它可以获取请求头、请求参数、请求方法等。response主要用于响应相关的设置和操作。什么是回应?也就是说,我收到了客户的请求。我可以设置状态码为200,返回数据给前端;或者设置状态码为500,并向前端返回错误。总之,调用接口返回什么,由响应决定。实际上createServer返回的是一个EventEmitter,所以上面的写法等价于这样:consthttp=require('http')constserver=http.createServer()server.on('request',(request,response)=>{response.statusCode=200response.end('helloworld')}).listen(3000)request解析用户发起的请求的相关数据,都包含在request对象中。这些数据包括常用的请求方法、请求头、url、请求体等数据。const{method,url,headers}=requestmethod表示可以直接使用请求方法,headers返回请求头对象,比较好用:const{headers}=requestconstuserAgent=headers['user-agent']//请求头都是只有小写字母不容易解析的url字符串,其中包含协议、主机名、路径、查询等。幸运的是,Node.js提供了url和querystring两个模块来解析url字符串。URL解析,先看url模块的例子:consturl=require('url')//解析url字符串varstring='http://localhost:8888/start?foo=bar&hello=world'varurl_object=网址。parse(string)//{protocol:'http:',host:'localhost:8888',pathname:'/start',query:'foo=bar&hello=world'}你看,url模块可以转换一个完整的URL地址字符串,拆分为包含每个部分属性的对象。但是有一个美中不足的地方,其他部分都解析出来了,只有query还是一个字符串。查询需要二次解析。怎么做?这时候第二个模块querystring就派上用场了:constquerystring=require('querystring')//解析查询字符串varstring='http://localhost:8888/start?foo=bar&hello=world'varurl_object=网址。parse(string)//{query:'foo=bar&hello=world'}varquery_object=querystring.parse(url_object.query)//{foo:'bar',hello:'world'}这是完美的。通过url+querystring的组合,您可以完全解析您的URL。请求体解析对于POST或PUT请求,我们需要接收请求体的数据。这里的requestbody比较特殊。不是一次性传输数据,而是通过Stream流进行流式传输,所以需要通过监听数据和结束事件一点点接收。获取方式如下:server.on('request',(request,response)=>{letbody=[]request.on('data',chunk=>{//这里的chunk是一个Bufferbody。push(chunk)})request.on('end',()=>{body=Buffer.concat(body)})console.log(body.toString())})response设置服务端接收客户端请求并通过response设置如何响应客户端。响应设置主要是三个部分:状态码、响应头、响应体。首先是状态码,比如404:response.statusCode=404然后是响应头:response.setHeader('Content-Type','text/plain')最后是响应体:response.end('Nodatafound')这三个部分也可以组合起来:response.writeHead(404,{'Content-Type':'text/plain','Content-Length':49}).end('Nodatafound')Sendhttp请求http模块除了接受客户端请求外,还可以作为客户端发送请求。发送http请求是指在Node.js中请求其他接口获取数据。发送请求主要是通过http.request方法实现的。GET下面是一个发送GET请求的简单例子:consthttp=require('http')constoptions={hostname:'nodejs.cn',port:80,path:'/learn',method:'GET'}constreq=http.request(options,res=>{console.log(`statuscode:${res.statusCode}`)res.on('data',d=>{process.stdout.write(d)})res.on('end',()=>{})})req.on('error',error=>{console.error(error)})req.end()使用http发送请求后。请求,必须显式调用req.end()以指示请求发送完成。POST与上面的GET请求基本相同,区别在于如何传递请求体:consthttp=require('http')constoptions={hostname:'nodejs.cn',port:80,path:'/learn',method:'POST'}constbody={sex:'man',name:'ruims'}constreq=http.request(options,res=>{console.log(`statuscode:${res.statusCode}`)res.on('data',d=>{process.stdout.write(d)})res.on('end',()=>{})})req.on('error',error=>{console.error(error)})req.write(JSON.stringify(body))//传递body参数的写法req.end()很奇怪看这里,如果你没有深入了解nodejs,你可能会发现几个地方令人毛骨悚然的地方。比如正常情况下POST请求传递的body参数可能是这样的:varbody={desc:'请求体参数'}varreq=http.request({path:'/',method:'POST',data:body})而上面说的正确姿势是这样的:varbody={desc:'请求body参数'}varreq=http.request({path:'/',method:'POST'})req.write(JSON.stringify(body))和上面获取请求体一样。不能直接通过request.body获取,必须这样:letbody=[]request.on('data',chunk=>{body.push(chunk)})request.on('end',()=>{body=Buffer.concat(body)})这些应该是大家理解http模块最容易混淆的地方。其实深究起来,这不是http的难点,而是Node.js中Stream特有的语法。其实http模块的核心---request和response都属于Stream,一个是可读流,一个是可写流。因此,要想吃透http模块,还需要深入了解Stream流的相关知识。总结本文基于最基本的http模块搭建了一个简单的HTTP服务器,实现了简单的接收和发送请求。然而,真实的应用场景一般不会这样匹配。社区成熟稳定的express框架,更适合编写Node.js服务;发送请求,我们可以使用最熟悉的axios——是的,axios也可以用在Node.js中。但是你可能不知道,express和axios的核心功能都是基于http模块的。因此,基础非常重要。地基不牢,地动摇。掌握http模块后,即使看到express中Stream的用法,也不会不知所措。本篇就到此为止,下篇文章继续探索Stream,记得关注我哦。以往本专栏会长期输出前端工程和架构方向的文章,特刊如下:以Vuex为向导,一窥状态管理。前端架构师的git技能,你有多牛?前端架构师的神技,统一代码风格的三种方式如果喜欢我的文章,请点赞支持!也欢迎关注我的专栏。免责声明:本文为原创,如需转载请微信联系ruidoc获得授权。