Skip to content

Commit a2aa6b5

Browse files
committed
2021.05.25
1 parent 6d7f1e5 commit a2aa6b5

9 files changed

Lines changed: 216 additions & 0 deletions

File tree

Cute-Gist/HTTP/.DS_Store

6 KB
Binary file not shown.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// https://github.com/a1029563229/blogs/blob/master/Introduction/http/README.md
2+
import http from './src/Http';
3+
4+
const server = http.createServer((req, res) => {
5+
res.setHeader('Content-Type', 'application/json')
6+
res.end(200, JSON.stringify(req.httpMessage));
7+
});
8+
9+
server.listen(8888, () => {
10+
console.log("server is listening in 8888...");
11+
});
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"name": "WriteHTTP-TS",
3+
"version": "1.0.0",
4+
"description": "",
5+
"main": "index.js",
6+
"scripts": {
7+
"start": "ts-node-dev --compiler ntypescript --project tsconfig.json index.ts"
8+
},
9+
"devDependencies": {
10+
"ntypescript": "^1.201706190042.1+a2776648cd48d4937b076fb8b3e935d3d5fb27e1",
11+
"ts-node": "^8.4.1",
12+
"ts-node-dev": "^1.0.0-pre.44",
13+
"typescript": "^3.6.4"
14+
},
15+
"keywords": [],
16+
"author": "",
17+
"license": "ISC"
18+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import * as net from 'net';
2+
import * as EventEmitter from 'events';
3+
import RequestMessage from "./RequestMessage";
4+
import ResponseMessage from "./ResponseMessage";
5+
6+
type Handler = (request: RequestMessage, response: ResponseMessage) => void;
7+
8+
const defaultPort = 3000;
9+
10+
class HTTP extends EventEmitter{
11+
handler: Handler;
12+
request: RequestMessage;
13+
response: ResponseMessage;
14+
server: net.Server;
15+
socket: net.Socket;
16+
constructor(handler: Handler){
17+
super();
18+
this.handler = handler;
19+
this.createServer();
20+
}
21+
22+
private createServer(): void {
23+
this.server = net.createServer(socket => {
24+
socket.on('data', (data: Buffer) => {
25+
const message = data.toString('utf-8');
26+
this.request = new RequestMessage(message);
27+
this.response = new ResponseMessage(socket);
28+
this.handler(this.request, this.response); // 返回 req res
29+
});
30+
31+
socket.on('error', error => {
32+
this.emit('error', error);
33+
})
34+
})
35+
}
36+
37+
public listen(port: number = defaultPort, callback: any = () => {}) : void{
38+
this.server.listen(port, callback);
39+
this.server.on('error', error => this.emit('error', error));
40+
}
41+
}
42+
43+
const createServer = (handler: Handler) => {
44+
return new HTTP(handler);
45+
}
46+
47+
export default {
48+
createServer
49+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
export type Headers = { [key: string]: string};
2+
3+
export type HttpMessage = {
4+
method: string;
5+
url: string;
6+
version: string;
7+
headers: Headers;
8+
body: string;
9+
}
10+
11+
export default class HttpParser {
12+
private message: string;
13+
public httpMessage: HttpMessage = null;
14+
15+
constructor(message: string){
16+
this.message = message;
17+
this.parse();
18+
}
19+
20+
private parse(): void {
21+
this.httpMessage = {} as HttpMessage;
22+
const messages = this.message.split("\r\n"); // 区分 header 和 body
23+
const [head] = messages;
24+
const header= messages.slice(1, -2);
25+
const [body] = messages.slice(-1);
26+
this.parseHead(head);
27+
this.parseHeader(header);
28+
this.parseBody(body);
29+
}
30+
31+
private parseHead(headStr: string) {
32+
const [method, url, version] = headStr.split(' ');
33+
this.httpMessage.method = method;
34+
this.httpMessage.url = url;
35+
this.httpMessage.version = version;
36+
}
37+
38+
private parseHeader(headerStr: string[]) {
39+
this.httpMessage.headers = {};
40+
for(let i = 0; i < headerStr.length; i ++){
41+
let [key, value] = headerStr[i].split(' ');
42+
this.httpMessage.headers[key.toLocaleLowerCase()] = value.trim();
43+
}
44+
}
45+
46+
private parseBody(bodyStr: string) {
47+
if(!bodyStr) return this.httpMessage.body = '';
48+
this.httpMessage.body = bodyStr;
49+
}
50+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import HttpParser, { HttpMessage } from "./HttpParser";
2+
3+
export default class RequestMessage {
4+
private httpParser: HttpParser;
5+
public httpMessage: HttpMessage;
6+
7+
constructor(message: string){
8+
this.httpParser = new HttpParser(message);
9+
this.httpMessage = this.httpParser.httpMessage;
10+
}
11+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { Headers } from './HttpParser';
2+
3+
export default class ResponseFormatter {
4+
private status: number = 200;
5+
private message: string = 'ok';
6+
private version: string = 'HTTP/1.1';
7+
private headers: Headers = null;
8+
private body: string = '';
9+
10+
constructor(){
11+
this.headers = {
12+
'Content-Type': 'text/plain'
13+
}
14+
}
15+
16+
public setStatus(status: number){
17+
this.status = status;
18+
}
19+
20+
public setBody(body: string){
21+
this.body = body;
22+
}
23+
24+
public setHeader(key: string, val: string) {
25+
this.headers[key] = val;
26+
}
27+
28+
public format(): string {
29+
const head = `${this.version} ${this.status} ${this.message}`;
30+
let headers = '';
31+
for(let k in this.headers){
32+
headers += `${k.toLocaleLowerCase()}: ${this.headers[k]}\r\n`;
33+
}
34+
return [head, headers, this.body].join('\r\n');
35+
}
36+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as net from 'net';
2+
import HttpParser, { HttpMessage } from "./HttpParser";
3+
import ResponseFormatter from './ResponseFormatter';
4+
5+
export default class ResponseMessage {
6+
private socket: net.Socket;
7+
private resFormatter: ResponseFormatter;
8+
9+
constructor(socket: net.Socket){
10+
this.socket = socket;
11+
this.resFormatter = new ResponseFormatter();
12+
}
13+
14+
public setHeader(key: string, value: string){
15+
this.resFormatter.setHeader(key, value);
16+
}
17+
18+
public end(status: number, body: string) {
19+
const resFormatter = this.resFormatter;
20+
resFormatter.setStatus(status);
21+
resFormatter.setBody(body);
22+
// 向客户端发送 TCP 字节流数据
23+
this.socket.write(resFormatter.format());
24+
this.socket.pipe(this.socket);
25+
this.socket.end();
26+
}
27+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"compilerOptions": {
3+
"target": "es2017",
4+
"module": "commonjs",
5+
"baseUrl": ".",
6+
"rootDir": ".",
7+
"noImplicitAny": true,
8+
"allowJs": true
9+
},
10+
"exclude": [
11+
"node_modules",
12+
"dist"
13+
]
14+
}

0 commit comments

Comments
 (0)