当前位置: 首页 > 后端技术 > Node.js

Koa源码阅读-详解

时间:2023-04-03 12:28:04 Node.js

继承上一章Applicationfunctionmodule.exports=classApplicationextendsEmitter{constructor(){super();this.proxy=false;这个.middleware=[];this.subdomainOffset=2;this.env=process.env.NODE_ENV||'发展';//context、request、response都是空对象,可以访问对应原型对象上的属性和方法this.context=Object.create(context);this.request=Object.create(请求);this.response=Object.create(response);}}EmitterApplication继承自EmitterEmitter,主要是观察订阅者模式,可以写在index.js中,结果会出现constapp=newKoa();app.on('a',(element)=>{//111console.log(element)})app.emit('a',111)了解Object.createconsta={a:1,b:2}constb=Object.create(a);//{}console.log(b.__proto__===a)//trueconsole.log(b.a)//1a在b的原型链上,b可以访问一个Attributes单元测试toJSON(){returnonly(这个,['subdomainOffset','proxy','env']);}inspect(){返回this.toJSON();}onlyfunctionreturnsnewobject并且只返回Containskey,key的值不为nullmodule.exports=fu函数(obj,键){obj=obj||{};if('string'==typeofkeys)keys=keys.split(/+/);returnkeys.reduce(function(ret,key){if(null==obj[key])returnret;ret[key]=obj[key];returnret;},{});};//执行应用程序.inspect()describe('app.inspect()',()=>{it('应该工作',()=>{constapp=newKoa();constutil=require('util');conststr=util.inspect(app);//如果相等则通过assert.equal("{subdomainOffset:2,proxy:false,env:'test'}",str);});});这里有个问题,为什么index.js实例后面只有这3个对象的属性???listencallslisten执行回调listen(){debug('listen');constserver=http.createServer(this.callback());返回server.listen.apply(服务器,参数);}callback(){constfn=compose(this.middleware);if(!this.listeners('error').length)this.on('error',this.onerror);consthandleRequest=(req,res)=>{res.statusCode=404;constctx=this.createContext(req,res);constonerror=错误=>ctx.onerror(错误);consthandleResponse=()=>respond(ctx);onFinished(res,onerror);fn(ctx).then(handleResponse).catch(onerror);};返回句柄请求;顺便说一下,本机HTTP创建这样的服务:consthttp=http.createServer((req,res)=>{res.writeHead(200,{'Content-Type':'text/plain'});res.end('okay');});http.listen(8000)createContextcreateContext(req,res){//基于this.context创建对象,此时引入的this.context已经实例化了两次请求和响应是一样的,都是作为属性挂在context上的constcontext=Object.create(this.context);constrequest=context.request=Object.create(this.request);constresponse=context.response=对象。创建(这个。响应);//上下文请求响应可以得到this,req,rescontext.app=request.app=response.app=this;context.req=request.req=response.req=req;上下文.res=request.res=response.res=res;//请求响应有上下文;request.ctx=response.ctx=上下文;//request和response可以得到自己的对象request.response=response;回复。请求=请求;//context和request的originalUrl有req.urlcontext.originalUrl=request.originalUrl=req.url;//context可以获取cookiescontext.cookies=newCookies(req,res,{keys:this.keys,secure:request.secure});request.ip=request.ips[0]||req.socket.remoteAddress||'';context.accept=request.accept=接受(请求);context.state={};//returncontextreturncontext;}respond由中间件处理,respondfunctionrespond(ctx){//允许绕过koaif(false===ctx.respond)return;constres=ctx.res;如果(!ctx.writable)返回;//获取bodyletbody=ctx.body;constcode=ctx.status;//如果主体不存在,则返回默认未找到//状态bodyif(null==body){body=ctx.留言||字符串(代码);如果(!res.headersSent){ctx.type='text';ctx.length=Buffer.byteLength(body);}返回res.end(body);}//如果body是Binary,就是字符串,Stream流,直接返回//responsesif(Buffer.isBuffer(body))returnres.end(body);if('string'==typeofbody)returnres.end(body);if(bodyinstanceofStream)returnbody.pipe(res);//body:jsonjson处理body=JSON.stringify(body);如果(!res.headersSent){ctx.length=Buffer.byteLength(body);}res.end(body);}context函数主要处理onerror和前面暴露的属性。最重要的/***上下文可以在response下使用attachmentredirect的方法,*可以在response下设置statusmessage的属性,*可以读取headerSent和writable*/delegate(proto,'response').method('attachment').method('redirect').method('remove').method('vary').method('set').method的值('append').method('flushHeaders').access('status').access('message').access('body').access('length').access('type').access('lastModified').access('etag').getter('headerSent').getter('writable');functionDelegator(proto,target){//调用函数是返回实例后的self,每次调用都是与此不同,好处是可以调用原型对象上的方法if(!(thisinstanceofDelegator))returnnewDelegator(proto,target);this.proto=proto;this.target=目标;这个.methods=[];这个.getters=[];this.setters=[];this.fluents=[];}//在proto上挂载target上的方法,但是执行的this是target的Delegator.prototype.method=function(name){varproto=this.proto;vartarget=this.target;这个.methods.push(名字);proto[name]=function(){returnthis[target][name].apply(this[target],arguments);};返回这个;};proto[name]可以读取target[name]Delegator.prototype.getter=fu函数(名称){varproto=this.proto;vartarget=this.target;this.getters.push(名字);proto.__defineGetter__(name,function(){returnthis[target][name];});returnthis;};proto[name]可以设置target[name]Delegator.prototype.setter=function(name){varproto=this.proto;vartarget=this.target;this.setters.push(名字);proto.__defineSetter__(name,function(val){returnthis[target][name]=val;});返回这个;};可读可写Delegator.prototype.access=function(name){returnthis.getter(name).setter(name);};请求对象总之,请求对象主要用于获取请求的信息。让我们看几个例子//Returnthis.req.headersinformationgetheader(){returnthis.req.headers;},get(field){constreq=this.req;switch(field=field.toLowerCase()){case'referer':case'referrer':returnreq.headers.referrer||}req.headers.referer||'';默认值:返回req.headers[field]||'';}},//获取请求头内容getlength(){constlen=this.get('Content-Length');如果(长度=='')返回;return~~len;},//获得query信息getquerystring(){if(!this.req)return'';返回解析(this.req).query||'';}response对象response对象主要做了相关头的信息set(field,val){if(2==arguments.length){if(Array.isArray(val))val=val.map(String);否则val=String(val);this.res.setHeader(field,val);}else{for(constkeyinfield){this.set(key,field[key]);}}},设置lastModified(val){if('string'==typeofval)val=newDate(val);this.set('Last-Modified',val.toUTCString());},setetag(val){if(!/^(W\/)?"/.test(val))val=`"${val}"`;this.set('ETag',val);}redirect(url,alt){//位置if('back'==url)url=this.ctx.get('Referrer')||alt||'/';this.set('Location',url);//状态if(!statuses.redirect[this.status])this.status=302;//htmlif(this.ctx.accepts('html')){url=escape(url);this.type='文本/html;字符设置=utf-8';this.body=`重定向到${url}.`;返回;}//文本this.type='text/plain;字符集=utf-8';this.body=`Redirectingto${url}.`;}结合官网看上面的比较好,?感谢您的阅读,您的喜欢是我写文章的动力git博客地址

猜你喜欢