跳槽是每个人的职业生涯中都要经历的过程,不论你是搜索到的这篇文章还是无意中浏览到的这篇文章,希望你没有白白浪费停留在这里的时间,能给你接下来或者以后的笔试面试带来一些帮助。
也许是互联网未来10年中最好的一年。WINTER IS COMING。但是如果你不真正的自己去尝试尝试,你永远不知道市面上的行情如何。这次找工作下来,我自身感觉市场并没有那么可怕,也拿到了几个大厂的offer。在此进行一个总结,给自己,也希望能帮助到需要的同学。
面试准备
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
面试准备根据每个人掌握的知识不同,准备的时间也不一样。现在对于前端岗位,以前也许不是很重视算法这块,但是现在很多公司也都会考。建议大家平时有空的时候多刷刷leetcode。算法的准备时间比较长,是一个长期的过程。需要在掌握了大部分前端基础知识的情况下,再有针对性的去复习算法。面试的时候算法能做出来肯定加分,但做不出来也不会一票否决,面试官也会给你提供一些思路。
app.listen(3000)
可以正常访问
app.use
在前置知识中我们看到,app.use接收一个回调函数,同时传入一个ctx上下文,这里ctx将request和response封装起来。为了清晰易懂,我们先不进行上下文的封装。
app.use(async ctx => {
ctx.body = ‘Hello World’;
});
那么use简单的处理如下:
class Application {
use(fn) {
this.fn=fn
}
}
此时use接收了一个函数,这个函数的执行的时机是在访问网站的时候,那么此时就需要在创建http服务的时候,传入这个函数。最好的方式就是放在listen的callbak中调用。
callback = (req, res) => {
this.fn(req, res)
}
最终代码
let http = require(‘http’)
class Application {
use(fn) {
this.fn=fn
}
callback = (req, res) => {
this.fn(req, res)
}
listen() {
const server = http.createServer(this.callback);
server.listen(…arguments)
}
}
module.exports = Application
测试:test.js
const Koa=require(‘./application.js’)
const app=new Koa()
app.use((req, res) => {
res.end(‘Hello World\n’);
})
app.listen(3000)
可以正常访问
明确一个事实:每个请求都是独立的,对于原生的http请求来说,每次请求的response和request是不同的。对于koa中的ctx,则表示每次请求的ctx都是一个新的ctx。
ctx的结构
为了看到ctx的结构,我们先使用源koa打印一下ctx。最终得到的结果如下所示,有了这个结构我们就可以实现一个自己的ctx。
下面这个格式是console.dir(ctx)的结果(删掉了一些具体的内容),从下面的内容,我们可以得出ctx的结构。。
{
request: {
app: Application {
},
req: IncomingMessage {
},
res: ServerResponse {
},
ctx: [Circular],
response: {
app: [Application],
req: [IncomingMessage],
res: [ServerResponse],
ctx: [Circular],
request: [Circular]
},
originalUrl: ‘/’
},
response: {
app: Application {
},
req: IncomingMessage {
},
res: ServerResponse {
},
ctx: [Circular],
request: {
app: [Application],
req: [IncomingMessage],
res: [ServerResponse],
ctx: [Circular],
response: [Circular],
originalUrl: ‘/’
}
},
app: Application {
},
req: IncomingMessage {
},
res: ServerResponse {
},
originalUrl: ‘/’,
state: {}
}
context.js
context.js 主要定义了context的具体结构以及提供的方法。
Koa Context 将 node 的 request
和 response
对象封装到单个对象中,为编写 Web 应用程序和 API 提供了许多有用的方法。 这些操作在 HTTP 服务器开发中频繁使用,它们被添加到此级别而不是更高级别的框架,这将强制中间件重新实现此通用功能。
request.js和response.js文件
在核心目录,我们提到了这两个文件,这两个文件此时就派上了用场。这两个文件具体实现了啥呢?这两个文件定义了ctx.resopnse和ctx.request的结构,也就是上面使用dir输出的结果。在koa中文文档中可以具体的看到结构,可以自行查阅。
Koa Request
对象是在 node 的 原生请求对象之上的抽象,提供了诸多对 HTTP 服务器开发有用的功能。
Koa Response
对象是在 node 的原生响应对象之上的抽象,提供了诸多对 HTTP 服务器开发有用的功能。
实现ctx
定义context.js
const context={
}
module.exports=context
定义request.js
const request={
}
module.exports=request
定义response.js
const resposne={
}
module.exports=response
use中封装ctx
我们在上面导出koa章节中可以看到,在app.use的时候,我们传的参数是(request,response),源koa传的的ctx,所以我们就知道了,koa是在app.use的时候创建了一个ctx。
在本章开头的时候,我们又提到每次请求的ctx都是全新的ctx。
综合以上两点,我们可以基本编写出下面的代码。(为了代码的清晰易读,我们封装了一个createcontext函数来创建上下文。)
const Context = require(‘./context’)
const Request = require(‘./request’)
const Response = require(‘./response’)
class Application {
constructor(){
this.context = Object.create(Context);
this.request = Object.create(Request);
this.response = Object.create(Response);
}
use(fn) {
this.fn = fn
}
createContext = (req, res) => {
const ctx = Object.create(this.context);
const request = Object.create(this.request);
const response = Object.create(this.response);
ctx.app = request.app = response.app = this
ctx.request = request;
ctx.request.req = ctx.req = req;
ctx.response = response;
ctx.response.res = ctx.res = res;
ctx.originalUrl = request.originalUrl = req.url
ctx.state = {}
return ctx
}
callback = (req, res) => {
let ctx = this.createContext(req, res)
this.fn(ctx)
}
listen() {
const server = http.createServer(this.callback);
console.log(…arguments)
server.listen(…arguments)
}
}
首先我们在constructor中定义了一个context对象,这里会在constructor定义是因为Koa的app上默认导出context属性。
app.context
是从其创建ctx
的原型。您可以通过编辑app.context
为ctx
添加其他属性。这对于将ctx
添加到整个应用程序中使用的属性或方法非常有用,这可能会更加有效(不需要中间件)和/或 更简单(更少的require()
),而更多地依赖于ctx
,这可以被认为是一种反模式。
例如,要从
ctx
添加对数据库的引用:
app.context.db = db();
app.use(async ctx => {
console.log(ctx.db);
});
然后再callback中,我们针对response和request进行了二次封装。
再来看看这段代码:
app.context.db = db();
app.use(async ctx => {
console.log(ctx.db);
});
再使用use之前,通过app.context对context进行了修改。当使用use函数的时候,是不是直接进入了callback函数,此时的this.context已经是修改过的了。
测试
const Koa=require(‘./application.js’)
const app=new Koa()
app.use((ctx) => {
// 测试1
ctx.response.res.end(" hello my koa")
// 测试2
ctx.res.end(" hello my koa")
})
app.listen(3000,()=>{
console.log(‘3000’)
})
正常访问!
明确一个事实:request类的属性是通过getter和setter设置的。为什么会这样设置?这样设置的好处是可以方便的设置和获取到值。是不是有点懵逼!请听我细细道来。
先来看一下Koa中request类所绑定的属性,官方链接。
我这里简单的列举几个:
request.header=
设置请求头对象。
request.headers
请求头对象。别名为 request.header
.
request.headers=
设置请求头对象。别名为 request.header=
request.url
获取请求 URL.
request.url=
设置请求 URL, 对 url 重写有用。
request.originalUrl
获取请求原始URL。
- 这里对于每个属性都有设置和获取的功能,使用getter和setter可以很好的实现。
get url () {
return this.req.url
},
- 这里的每个属性是如何设置的,如果我们对request本身设置有效吗?
const request={
url:‘’,
header:{
}
}
const request={
set url (val) {
this.req.url = val
}
get url () {
return this.req.url
},
}
request.socket的getter
socket在这里指套接字。套接字的概念这里不赘述!
get socket () {
return this.req.socket
},
request.protocol的getter
返回请求协议,“https” 或 “http”。当 app.proxy
是 true 时支持 X-Forwarded-Proto
。
先判断套接字中是否存在encrypted(加密),如果加密,就是https,
X-Forwarded-Proto用来确定客户端与代理服务器或者负载均衡服务器之间的连接所采用的传输协议(HTTP 或 HTTPS)
X-Forwarded-Proto: https
X-Forwarded-Proto: http
get protocol () {
if (this.socket.encrypted) return ‘https’
if (!this.app.proxy) return ‘http’
const proto = this.get(‘X-Forwarded-Proto’)
return proto ? proto.split(/\s*,\s*/, 1)[0] : ‘http’
},
这里有一个get函数,主要时根据字段,从请求头中获取数据。
get (field) {
const req = this.req
switch (field = field.toLowerCase()) {
case ‘referer’:
case ‘referrer’:
return req.headers.referrer || req.headers.referer || ‘’
default:
return req.headers[field] || ‘’
}
},
request.host的getter
存在时获取主机(hostname:port)。当 app.proxy
是 true 时支持 X-Forwarded-Host
,否则使用 Host
。
get host () {
const proxy = this.app.proxy
let host = proxy && this.get(‘X-Forwarded-Host’)
if (!host) {
if (this.req.httpVersionMajor >= 2) host = this.get(‘:authority’)
if (!host) host = this.get(‘Host’)
}
if (!host) return ‘’
return host.split(/\s*,\s*/, 1)[0]
},
request.origin的getter
获取URL的来源,包括 protocol
和 host
。
例如我请求:http://localhost:3000/index?a=3,
origin返回的是http://localhost:3000
get origin () {
return ${this.protocol}://${this.host}
},
request.href的getter
获取完整的请求URL,包括 protocol
,host
和 url
。
href支持解析 GET http://example.com/foo
例如我访问http://localhost:3000/index?a=3
href返回http://localhost:3000/index?a=3
get href () {
if (/^https?😕//i.test(this.originalUrl)) return this.originalUrl
return this.origin + this.originalUrl
},
注意:这里的this.originalUrl在封装ctx的时候已经绑定过了
request.header 的getter和setter
请求头对象。这与 node http.IncomingMessage
上的 headers
字段相同
get header () {
return this.req.headers
},
set header (val) {
this.req.headers = val
},
request的属性是很多的,我们就不展开了,反正知道了原理,大家慢慢自己加吧。
对比request的封装,response的封装稍微有些不同,因为,对于request来说大部分的封装是getter,而response的封装大部分都是setter
在request部分我们阐述了三个使用getter和setter的原因。在resposne中最主要的原因我觉得是改变set的对象。
其实想一想很简单,例如在网络请求中我们会经常遇到各种状态:404 200等等,这些在node的http模块中,是用resposne.status进行改变的。假设我们在koa的response直接设置,你觉得会有用吗?简单概括一句话:koa的request和respsone是对nodehttp模块的二次封装,并且底层还是对nodehttp模块的操作。
response.status的getterh和setter
获取响应状态。默认情况下,response.status
设置为 404
而不是像 node 的 res.statusCode
那样默认为 200
。
默认’404’,这里的默认是在何时默认的时候呢,其实是在接收到请求后就设置为404,也就是说在callback的时候开始设置为404。(注意:http中res.statusCode用来标记状态码,在Koa中这个被封装成status)
callback = (req, res) => {
let ctx = this.createContext(req, res)
const res = ctx.res
res.statusCode = 404
this.fn(ctx)
}
response.status的实现
get status () {
return this.res.statusCode
},
set status (code) {
if (this.headerSent) return
跳槽是每个人的职业生涯中都要经历的过程,不论你是搜索到的这篇文章还是无意中浏览到的这篇文章,希望你没有白白浪费停留在这里的时间,能给你接下来或者以后的笔试面试带来一些帮助。
也许是互联网未来10年中最好的一年。WINTER IS COMING。但是如果你不真正的自己去尝试尝试,你永远不知道市面上的行情如何。这次找工作下来,我自身感觉市场并没有那么可怕,也拿到了几个大厂的offer。在此进行一个总结,给自己,也希望能帮助到需要的同学。
面试准备
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
面试准备根据每个人掌握的知识不同,准备的时间也不一样。现在对于前端岗位,以前也许不是很重视算法这块,但是现在很多公司也都会考。建议大家平时有空的时候多刷刷leetcode。算法的准备时间比较长,是一个长期的过程。需要在掌握了大部分前端基础知识的情况下,再有针对性的去复习算法。面试的时候算法能做出来肯定加分,但做不出来也不会一票否决,面试官也会给你提供一些思路。