当前位置: 首页 > 科技观察

如何开始编写前端第一个NodeServer:简单来说从请求到响应

时间:2023-03-14 20:39:56 科技观察

本文涉及到以下库和模块:mime:parseMIMETYPEmime-typesparseurl:用于解析URL。您还可以使用本机模块url。qs:用于继续querystring。同时也可以使用原生模块querystring,不过已经弃用了。推荐使用URLSearchParams。raw-body:用于解析正文。服务器端框架是对HTTP协议的高层封装,是对HTTP报文的解析和处理。因此,学习NodeServer的第一步是从一条HTTP报文开始。HTTP报文下面是一个简单的向百度发起请求的HTTP报文格式。使用nc命令行工具从HTTP消息发起连接请求并接收响应。$ncwww.baidu.com80GET/HTTP/1.1主机名:www.baidu.comHTTP/1.1200OKAccept-Ranges:bytesCache-Control:no-cacheConnection:keep-aliveContent-Length:14615Content-Type:text/htmlDate:Sun,04Jul202105:26:21GMTP3p:CP="OTIDSPCORIVAOURINDCOM"P3p:CP="OTIDSPCORIVAOURINDCOM"Pragma:no-cacheServer:BWS/1.1Set-Cookie:BAIDUID=062BC32733955287CAD249DFFA961C83:FG=1;expires=Thu,31-Dec-3723:55:55GMT;max-age=2147483647;path=/;domain=.baidu.comSet-Cookie:BIDUPSID=062BC32733955287CAD249DFFA961C83;expires=Thu,31-Dec-3723:55:55GMT;max-age=2147483647;path=/;domain=.baidu.comSet-Cookie:PSTM=1625376381;expires=Thu,31-Dec-3723:55:55GMT;max-age=2147483647;path=/;domain=.baidu.comSet-Cookie:BAIDUID=062BC3273395528798622D3D30510E2B:FG=1;max-age=31536000;expires=Mon,04-Jul-2205:26:21GMT;domain=.baidu.com;path=/;version=1;comment=bdTraceid:1625376381035471002611003607825099517305Vary:Accept-EncodingX-Ua-Compatible:IE=Edge,chrome=1百度一下就知道了...我们把报文分成以下几部分,稍微解析一下RequestMethod节点服务器中的路径HTTP版本请求标头响应ResponseStatusCodeResponseHeaderResponseBodySimpleServer:hello,world在Node.js中写一段简单的服务器端代码非常简单。它只需要以下三行即可。http是实现这一点的核心模块。consthttp=require('http')constserver=http.createServer((req,res)=>res.end('hello,world'))server.listen(3000)此时访问http://localhost:3000,你可以看到一个你好,世界页面。最简单的服务端应用就完成了。$nclocalhost3000GET/HTTP/1.1HTTP/1.1200OKDate:Sun,04Jul202108:54:45GMTConnection:keep-aliveKeep-Alive:timeout=5Content-Length:12hello,world下面是关于createServer的核心API,其中req对应初始解析请求消息,res对应响应消息的处理和设计,比如上面状态码和几个响应头的处理。函数createServer(requestListener?:RequestListener):Server;typeRequestListener=(req:IncomingMessage,res:ServerResponse)=>void;classIncomingMessageextendsstream.Readable{constructor(socket:Socket);aborted:boolean;httpVersion:string;httpVersionMajor:number:httpVersionMinor数字;完成:布尔值;连接:套接字;套接字:套接字;标头:IncomingHttpHeaders;rawHeaders:字符串[];拖车:NodeJS.Dict<字符串>;rawTrailers:字符串[];设置超时(毫秒:数字,回调?:()=>void):this;method?:string;url?:string;statusCode?:number;statusMessage?:string;destroy(error?:Error):void;}上面的JSONAPI和Content-Type只是一个hello,世界上的例子,但大部分实际项目都是JSONAPI设计。我们如何响应JSON数据?为了正确发送带有中文信息的响应报文,我们做如下设置:constserver=http.createServer((req,res)=>{res.setHeader('Content-Type','application/json;charset=utf-8');constdata=JSON.stringify({username:'MountainMoon'})res.end(data)})$nclocalhost3000GET/jsonHTTP/1.1HTTP/1.1200OKContent-Type:application/json;charset=utf-8Date:Sun,04Jul202111:03:05GMTConnection:keep-aliveKeep-Alive:timeout=5Content-Length:21{"username":"MountainMoon"}响应JSON数据需要设置特殊的Content-Type,即MIME。除了JSON,图片和视频还有不同的MIME类型,可以通过以下参数获取。mimemime-types>mime.getType('json')"application/json">mime.getType('html')"text/html">mime.getType('svg')"image/svg+xml">mime.getType('jpg')"image/jpeg"如何处理用户输入:URL和QueryString解析在服务器应用中,需要将请求地址解析成各种参数以便于调用,比如常用的主机名、路径、和查询字符串。实际上,当一个请求来的时候,我们只能拿到一个req.url,其他的参数需要我们自己去解析。毕竟自己动手,丰衣足食。可以使用以下库解析URL。parseurl:用于解析URL。您还可以使用本机模块url。qs:用于继续querystring。同时也可以使用原生模块querystring,不过已经弃用了。推荐使用URLSearchParams。这两种都是服务端常用的库,一般面试也会要求手写代码。“为了提高性能,各大服务器框架一般都使用get/set来进行延迟计算。”以下为koa源码constrequest={getpath(){returnparse(this.req).pathname;},setpath(path){consturl=parse(this.req);if(url.pathname===path)return;网址。pathname=path;url.path=null;this.url=stringify(url);},getquery(){conststr=this.querystring;constc=this._querycache=this._querycache||{};returnc[str]||(c[str]=qs.parse(str));},setquery(obj){this.querystring=qs.stringify(obj);},}如何处理用户输入:请求主体解析为JSONAPI中的输入传递参数,除了在URL上传递参数外,最流行、最常用、最安全的方法是在NodeServer中。我们的HTTPRequest是基于ReadableStream的,所以解析请求体(RequestBody)可能不是一个很重要的工作。简单的东西需要涉及到读取流、编码、解析格式、gzip解压、异常处理、超大413处理等,再简单的处理也涉及下面的代码。constserver=http.createServer((req,res)=>{letbody=''req.on('data',chunk=>body+=chunk)req.on('end',()=>{data=bodyres.end(data)})})"好在有一个body解析神器:raw-body。最流行的Node服务端框架Express和Koa都是基于raw-body来解析请求body的。“constserver=http.createServer((req,res)=>{getRawBody(req).then((body)=>{res.statusCode=200res.end(body)}).catch((err)=>{res.statusCode=500res.end(err.message)})})在JSONAPI中,虽然响应体是基于JSON的,但是请求体的格式还是有很多种的,比如最常见的:application/www-form-url-encodedapplication/jsonmultipart/form-datatext/plain如何处理不同的MIME请求体,我们会在下一篇分析!此时,服务端可以通过请求URL中携带的QueryString和RequestBody是输入,返回对应的响应体Node服务器框架详解KoaHapiNestFastify微总结本文从一段HTTP报文信息开始了解服务器,最后理清整个处理流程从requesttoresponse按照以下步骤:开始写第一个Nodehello,世界版服务器代码。y请求,响应数据总是hello,world。开始编写第一个NodeJSONAPI样式的服务器代码,这是hello,world的增强版本。无论任何请求,响应数据始终是JSON,响应主体类型由响应头Content-Type设置。通过解析请求报文的URL和QueryString,解析输入并响应相应的输出。通过解析请求消息的Body,解析输入,响应响应的输出。下一步呢?如何解析路由,解析body作为请求的输入时有哪些细节?JSONAPI的最后必要步骤序列化如何更有效地走向成熟。转载本文请联系全栈成长之路公众号。