HTTP协议1.1

打开chrome的调试面板,切换到network面板,搞清楚该页上所有的显示项、菜单、弹窗等下级功能的含义

  1. 什么是TTFB?TTFB包含了哪些部分?

Time to first byte,Timing里面的waiting,从http请求发送到服务器接收第一个字节的时间花费。

包含了TCP连接时间,http请求发送时间和服务器接收到第一个字节的时间。

  1. network面板里看到一个请求,怎么判断这个请求真的发送到了服务器那里?

根据状态码来看,502和504是没有发送到服务器,304从浏览器读取缓存。

  1. 一条请求变红了可能是因为哪些原因?

4,5开头的状态码,插件阻拦,浏览器的一些约定和协议

HTTP协议的特征:

  1. 两方通信
  2. 非对等的通信双方(server/client)
  3. 通信的基本单元(request和response)
  4. 请求与返回的对应关系

请写出一个简单的http请求:(method放前面,协议放后面)

初始行:method + path + 协议(GET /index.html HTTP/1.1\r\n HOST: www.maxtropy.com\r\n\r\n)

注:CRLF

  1. 回车 = CR = \r
  2. 换行 = LF = \n

HTTP基于TCP运行

TCP:两河模型

怎么知道一条请求已经结束了?答:\r\n

怎么区分前一条请求和后一条请求?答:\r\n\r\n

const str = "GET /index.html HTTP/1.1\r\nHost: www.maxtropy.com\r\n\r\nGET /main.js HTTP/1.1\r\nHost: www.maxtropy.com\r\n\r\n"
function parseRequest(str) {
    const result = [];
    const arr = str.split('\r\n\r\n');
    arr.forEach(item => {
        const data = item.split('\r\n');
        result.push({
            requestLine: data[0],
            headers: data[1].split()
        })
    })
}

写出一个带有body的http POST请求:

POST /index.html HTTP/1.1\r\n

HOST: www.maxtropy.com\r\n

Content-Length: 14\r\n\r\n

body: {json}

interface RequestObject {
    requestLine: string;
    headers: string[];
    body?: string;
}
class RequestProcessor {
    feed(rawData: string): void {
        
    }
    poll():RequestObject | undefined {
        return undefined;
    }
}
const str0 = 'POST /user/';
    const str1 = 'create HTTP/1.1\r\nHost: www.';
    const str2 = 'maxtropy.com\r\nqwee: Content-Length: 19\r\nContent';
    const str3 = '-Length: 19\r\n\r\n';
    const str4 = '{"name":"';
    const str5 = 'tom","\r\n"}POST';
    const str6 = ' /user/';
    const str7 = 'create HTTP/1.1\r\nHost: www.';
    const str8 = 'maxtropy.com\r\nContent';
    const str9 = '-Length: 21\r\n\r\n';
    const str10 = '{"name":"';
    const str11 = 'tom","\r\n\r\n"}';

    const test0 = "POST /index.js HTTP/1.1\r\nHost: www.test.com\r\nContent-Length:15\r\n\r\n{'name': 'tom'}GET /main.js HTTP/1.1\r\nHost: www.test.com\r\n\r\n";
    const test1 = "POST /index.js HTTP/1.1\r\nHost: www.test.com\r\nContent-Length: 17\r\n\r\nContent-Length=16GET /main.js HTTP/1.1\r\nHost: www.test.com\r\n\r\n";
    const test2 = "POST /index.js HTTP/1.1\r\nHost: www.test.com\r\nContent-Length: 9\r\n\r\nGET HOST:GET /main.js HTTP/1.1\r\nHost: www.test.com\r\n\r\n";
    const test3 = "POST /index.js HTTP/1.1\r\nHost: www.test.com\r\nContent-Length: 6\r\n\r\n\r\n\r\n\r\nGET /main.js HTTP/1.1\r\nHost: www.test.com\r\n\r\n";
    const test4 = "GET /main.js HTTP/1.1\r\nHost: www.test.com\r\n\r\nPOST /index.js HTTP/1.1\r\nHost: www.test.com\r\nContent-Length: 15\r\n\r\n{'name': 'tom'}";
    const test5 = "GET /main.js HTTP/1.1\r\nHost: www.test";
    const test6 = "POST /index.js HTTP/1.1\r\nHost: www.test.com\r\nContent-Length: 6\r\n\r\n\r\ntestGET /main.js HTTP/1.1\r\nHost: www.test.com\r\n\r\n";
    const test7 = "POST /index.js HTTP/1.1\r\nHost: www.test.com\r\nContent-Length: 15\r\n\r\n{'name': 'tom'}GET /main.js HTTP";
    const test8 = "POST /index.js HTTP/1.1\r\nHost: www.test.com\r\nContent-Length: 15\r\n\r\n{'name': 'tom'}GET /main.js HTTP/1.1\r\nHost: www.test.com";
    const test9 = "POST /index.js HTTP/1.1\r\nHost: www.test.com\r\nContent-Length: 15\r\n\r\n{'name': 'tom'}GET /main.js HTTP/1.1\r\nHost: www.test.com\r\n\r\nGET /main.js HTTP/1.1\r\nHost: www.test.com\r\n\r\n";
    const test10 = "POST /index.js HTTP/1.1\r\nHost: www.test.com\r\nContent-Length: 15\r\n\r\n{'name': GET GET /main.js HTTP/1.1\r\nHost: www.test.com\r\n\r\nGET /main.js HTTP/1.1\r\nHost: www.test.com\r\n\r\n";
    let result = [];
    let newUrl = '';
    function feed(rawData){
        newUrl = newUrl + rawData;
        let requestUrl = '';
        let indexArr = [];
        let firstIndex = -1;
        for (let i = 0;i < newUrl.length;i++) {
            if(String(newUrl[i] + newUrl[i+1] + newUrl[i+2] + newUrl[i+3]) === '\r\n\r\n') {
                requestUrl = newUrl.substring(0,i);
                firstIndex = i;
                break;
            }
        }
        for (let i = 0; i < requestUrl.length; i++) {
            if (String(requestUrl[i] + requestUrl[i + 1]) === '\r\n') {
                indexArr.push(i)
            }
        }
        if (firstIndex !== -1) {
            if (requestUrl.toLocaleUpperCase().indexOf('CONTENT-LENGTH:') === -1) { // 不带body
                result.push({
                    requestLine: requestUrl.substring(0, indexArr[0]),
                    headers: requestUrl.substring(indexArr[0]+2)
                });
                newUrl = newUrl.substring(requestUrl.length).trim();
                feed('')
            } else {
                const contentLength = Number(requestUrl.toLocaleUpperCase().trim().split('CONTENT-LENGTH:')[1]);
                //---- body尚不完整的情况
                if (newUrl.length >= requestUrl.length + contentLength + 4) {
                    result.push({
                        requestLine: requestUrl.substring(0, indexArr[0]),
                        headers: requestUrl.substring(indexArr[0] + 2, firstIndex).split('\r\n'),
                        body: newUrl.substr(firstIndex+4, contentLength)
                    });
                    newUrl = newUrl.substring(requestUrl.length + contentLength + 4);
                    feed('')
                }
            }
        }
    }
    function poll() {
        if(result.length) {
            const first = result[0];
            result.shift();
            return first
        }else {
            return undefined;
        }
    }
    // feed(str0);
    // console.log(poll());
    // feed(str1);
    // console.log(poll());
    // feed(str2);
    // console.log(poll());
    // feed(str3);
    // console.log(poll());
    // feed(str4);
    // console.log(poll());
    // feed(str5);
    // console.log(poll());
    // feed(str6);
    // console.log(poll());
    // feed(str7);
    // console.log(poll());
    // feed(str8);
    // console.log(poll());
    // feed(str9);
    // console.log(poll());
    // feed(str10);
    // console.log(poll());
    // feed(str11);
    // console.log(poll());
    feed(test3);
    console.log(poll(),poll(),poll());

分别写出一个带body和不带body的response:(协议放在前面)

不带body

HTTP/1.1 200 OK
max-age: 0

带body

HTTP/1.1 200 OK 
max-age: 0 
Content-Length: 14
{json}

请求及相应结构:

start-line + *(header-field CRLF) + CRLF + [message-body]

  1. HTTP为什么不能是多方通信?

request和response不能一一对应

  1. 怎么区分client和server?

通过发送的信息的结构

  1. server怎么向client主动发送数据?

webSocket,SSE,HTTP是不能实现的,因为client会把请求当响应处理报错

https://tools.ietf.org/html/rfc2119

延伸:

  1. 了解HTTP chunked编码及其使用场景

服务器返回的消息的长度,像前台给后台的Content-Length一样;transfer-coding的阈值为chunked时表示将用chunked编码传输内容;

使用场景:前台下载大文件

  1. 了解WebSocket的协议细节,与HTTP协议的不同之处

WebSocket 是基于TCP/IP协议,独立于HTTP协议的通信协议;双向通讯,有状态,客户端一(多)个与服务端一(多)双向实时响应(客户端 ⇄ 服务端);持久化协议;

GET /webfin/websocket/ HTTP/1.1
Host: localhost
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: xqBt3ImNzJbYqRINxEFlkg==
Origin: http://localhost:8080
Sec-WebSocket-Version: 13
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: K7DJLdLooIwIG/MOpvWFB3y3FE8=
  1. HTTP/1.1队头阻塞的问题

由于http一发一收的应答机制(请求-应答模型),如果队首的请求处理太慢就会阻塞后面的进程。

解决办法:并发连接,客户端对一个域名同时发起多个长连接,用数量来解决质量问题,但是如果并发数太大,服务器会认为是恶意攻击,拒绝请求,对客户端发起并发请求的数量限制在6-8;域名分片,增加域名的数量,多个域名指向同一个服务器。

长连接:不进行四次握手,数据传输完成TCP连接不断开,同域名下继续使用这个通道,有过期时间限制(keep-alive:timeout)

  1. 如果GET或DELETE请求,发送者带上了body,服务器应该怎样处理?

直接忽略body的内容(可能会导致下一个接口报错);报400,参数错误;接受处理,返回空数据;丢弃Content-Length和body

  1. 撰写测试用例
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,367评论 6 512
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,959评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,750评论 0 357
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,226评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,252评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,975评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,592评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,497评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,027评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,147评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,274评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,953评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,623评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,143评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,260评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,607评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,271评论 2 358