const Koa = require("koa");
const app = new Koa();
app.use((ctx) => {
ctx.body = 'Hello World!'
})
app.listen(3000)
复制代码
这就是咱们koa的使用了。其中ctx是koa的一大发明,它是koa的上下文。ctx包含了req和res。以上代码其实就是一个http服务,源码实现其实也就是要考虑在Node里的哪一个模块的哪一个方法能够实如今端口上实现服务监听。前端
// index.js文件
const MyKoa = require("./lib/application");
const app = new MyKoa();
app.use((req, res) => {
res.end('Hello World!')
})
app.listen(3000, () => {
console.log('你的应用在3000端口启动');
});
复制代码
// application.js文件
// 在index.js同级目录下建立lib文件,再建立子文件application.js文件
const http = require('http');
class MyKoa {
constructor() {
console.log('手写koa!')
// 初始化定义属性
this.fn = undefined;
}
// ...args动态接收参数
listen(...args) {
// 启动server传入异步的回调函数给用户反馈
let server = http.createServer(this.fn);
server.listen(...args);
}
use(fn) {
// 利用对象属性保存
this.fn = fn;
}
}
module.exports = MyKoa
复制代码
在这里请区分一下两个listen: app.listen和server.listen。第一个listen是koa的api,第二个listen是使用node原生代码来实现这个api。node
// server.js
const http = require('http');
http.createServer((req, res) => {
// 向前端返回的内容
res.end('OKOK!');
})
.listen(8088, ()=> {
console.log(8088);
})
复制代码
// 引入net模块(封装了传输层)
const net = require('net');
// 传输层 源端口号 目的地端口号
// 建立请求
// 建立一个到端口port和主机host的TCP链接(去到目的地址发起请求)
const client = net.createConnection({ port: 8088, host: '127.0.0.1' }, () => {
let json = JSON.stringify({a: 1});
// 一行一行拼接报文,空格也不能省
// 不区分URL,使用'/'
// CR LF为行结束符,用\r\n表示
client.write('POST / HTTP/1.1\r\n');
client.write('HOST: 127.0.0.1\r\n');
client.write('Content-Type: application/json\r\n');
// 首部和实体的分隔符
client.write('\r\n');
client.write(json);
// 报文拼接结束
client.write('\r\n');
})
// 服务器返回的数据
client.on('data', (data) => {
// 原始数据为Buffer,将其转换为字符串
console.log('receive:', data.toString());
})
// 接收完数据后断开
client.on('end', () => {
console.log('disconnect');
})
复制代码
const net = require('net');
class Xmlhttprequest {
constructor() {
// 放入属性保存
// 请求部分
this.method = null;
this.url = null;
this.headers = null;
this.body = null;
// 响应部分
this.resStatusLine = null;
this.resHeaders = null;
this.response = null;
}
// 设置操做
open(method, url) {
this.method = method;
this.url = url;
}
setHeader(headers) {
this.headers = headers;
}
// 切割报文
parse(string) {
const lines = string.split('\r\n');
console.log(lines);
this.resStatusLine = lines[0];
this.statusCode = this.resStatusLine.split(' ')[1];
this.resHeaders = lines.slice(1, lines.length - 2);
this.response = lines[lines.length - 1];
}
send(body) {
// 浏览器发出http请求后开始拼接http报文
this.body = body;
// 创建链接
const client = net.createConnection({ port: 8088, host: '127.0.0.1' }, () => {
// 拼接报文
client.write(`${this.method} ${this.url} HTTP/1.1\r\nHOST: 127.0.0.1\r\nContent-Type: application/json\r\nContent-Length: ${this.body.length}\r\n\r\n${this.body}\r\n`)
// 发送完毕
client.end();
})
// 收到后端返回的数据
client.on('data', (chunk) => {
// 服务端返回给浏览器的也是一个原始的http报文
// 解析报文
console.log('receive:', JSON.stringify(chunk.toString()));
// 调用专用的解析函数parse解析报文
this.parse(chunk.toString());
// 接受完数据后调用onload
this.onload();
})
client.on('end', () => {
console.log('disconnect');
})
}
}
// ajax
const xhr = new Xmlhttprequest();
xhr.open("POST", "/");
// 定义请求头
xhr.setHeader({
'Content-Type': 'application/json'
})
// 回调数据加载回来才会调用
xhr.onload = function() {
//
console.log('响应数据:');
// 拿到响应的状态码
console.log(xhr.statusCode)
// 拿到响应的内容
console.log(xhr.response)
// 拿到响应头
console.log(xhr.resHeaders)
}
// 发出请求
xhr.send(JSON.stringify({a: 1}))
复制代码
以上解析报文的方法并非最通用和最"优雅"的方法,它是一种比较古老的方法。但对咱们理解底层实现仍是有一点帮助的。ajax
在前端学习中,咱们会遇到各类各样的框架和API。咱们不能只停留在会用的阶段,而是要尽量地掌握底层实现的原理。毕竟,框架和API会一直更新换代,掌握底层最基本的原理才能以不变应万变。json