http协议篇

2019-01-21  本文已影响0人  三天两觉_

cors预请求(跨域的时候回出现预请求的验证 )

允许的方法有
  1. GET
  2. HEAD
  3. POST
允许的Content-Type有
  1. text/plain
  2. multipart/form-data
  3. application/x-www-form-urlencoded
其他限制
  1. 请求头限制

缓存Cache-Control

可缓存性(哪些地方可以去缓存)

到期

重新验证

其他

验证

const http = require('http');
const fs = require('fs');


http.createServer(function (request, response) {
    console.log('request come',request.url);

    if(request.url == '/'){
        const html = fs.readFileSync('test.html','utf-8');
        response.writeHead(200,{
            'Content-Type':'text/html'
        });
        response.end(html);
    }
    if(request.url == '/script.js'){
        const etag = request.headers['if-none-match'];
        if(etag === '777'){
            /**
             * 1.当写入头为304的时候,即使我们把Etag的值改变了,浏览器也不会重新拿到新资源,
             * 也不会更新响应头返回的Etag的新值,所以下次请求的时候用的还是老的Etag的值。
             * 2.当设置Cache-Control的值no-cache时候,如果响应头返回了Last-Modified和Etag的值,
             * 浏览器再次发送请求的时候会添加Last-Modified和Etag的请求头;
             * 当设置Cache-Control的值no-cache时候,即使应头返回了Last-Modified和Etag的值,
             * 浏览器再次发送请求也不会添加Last-Modified和Etag的请求头;
             **/
            response.writeHead(304,{
                'Content-Type':'application/javascript',
                'Cache-Control':'max-age=2000000,no-store',
                'Last-Modified':'123',
                'Etag':'7778'
            });
            response.end('some word')
        }else{
            response.writeHead(200,{
                'Content-Type':'application/javascript',
                'Cache-Control':'max-age=2000000,no-store',
                'Last-Modified':'123',
                'Etag':'777'
            });
            response.end('console.log("script loaded twice")');
        }
    }

}).listen(8888);

console.log('service listening on 8888');

Cookie

Cookie属性

const http = require('http');
const fs = require('fs');

http.createServer(function (request, response) {
    console.log('request come',request.url);
    const host = request.headers.host;
    if(request.url == '/'){
        const html = fs.readFileSync('./test.html','utf-8');
        /**注意,下面代码我们在a.test.com的域名设置domain的值为test.com,其实是不能成功的,也就是说不能
         * 在二级域名下设置一级域名的cookie;此时cookie不能被设置成功。
         * **/
        if(host==='a.test.com'){
            response.writeHead(200,{
                'Content-Type':'text/html',
                'Set-Cookie':['id=123;max-age=2','abc=456;HttpOnly','def=789;domain=test.com']
            });
    }
        response.end(html);
    };
}).listen(8888);

console.log('service listening on 8888');

修改代码

if(host==='test.com'){ 
      response.writeHead(200,{
          'Content-Type':'text/html',
          'Set-Cookie':['id=123;max-age=2','abc=456;HttpOnly','def=789;domain=test.com']
      });
}

此时是可以设置成功的,由于设置的domain的值是一级域名test.com。那么a.test.com以及b.test.com都会带上所设置的cookie。

Http长连接

发送http请求需要创建TCP连接,在http0.9和http1.0的时候每发送一次请求都需要建立创建一个TCP的连接,请求响应后这个连接就会关闭,下次发请求会重新创建TCP连接;http1.1之后包括http1.1是支持长连接的,意思是只创建一次TCP连接,
之后的请求都通过这个连接。我们打开百度,随意输入一个关键字去搜索,打开network截图如下:


image.png

图中有一列显示的是connectionID,connectionID相同表明是同一个TCP连接。http1.1的连接在TCP上发送请求是有先后顺序的,不能在同一个TCP连接上去并发的发送。我们在加载首页的时候是希望去并发的,因为这样效率会高一点;所以浏览器可以允许并发的创建TCP连接,数目会有限制,比如chrome浏览器限制的数量为6;


image.png
图中可以看出,connectionID为93370的TCP连接发送了三次请求,后一次请求要等待前一次的返回。

数据协商

分类

Redirect

const http = require('http');
http.createServer(function (request, response) {
    console.log('request come',request.url);
    if(request.url=='/'){
        response.writeHead(301,{
           'Location':'/new'
        });
        response.end('');
    }
    if(request.url=='/new'){
        response.writeHead(200,{
            'Content-Type':'text/html'
        });
        response.end('<h3>this is content</h3>');
    }
}).listen(8888);
console.log('service listening on 8888');

301(临时重定向)和302(永久重定向)区别是 302会先发送请求到服务端,服务端返回之后浏览器再次发送请求,一共发送了两次请求;302是服务端高告知浏览器如果再次出现某个资源的请求路径,直接在浏览器端改变求情资源的地址,所以只会发送一次请求。要特别注意的是,一旦做了301的跳转,浏览器会尽可能长时间的去做缓存,即使之后服务端修改了响应头,改为200,浏览器也是无感知的,除非是客户端用户自己手动清理浏览器的缓存才能得到新的响应资源,所以使用301一定要慎重。

CSP Content-Security-Policy 内容安全策略

作用

限制方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>scp</h3>
    <script>
        console.log('scp test...')
    </script>
    <script src="/test.js"></script>
    <script src="http://code.jquery.com/jquery-3.2.1.min.js"></script>
</body>
</html>

服务端 service.js

const http = require('http');
const fs = require('fs');

http.createServer(function (request, response) {
    console.log('request come',request.url);
    const html = fs.readFileSync('./test.html','utf-8');
    if(request.url==='/'){
        response.writeHead(200,{
            'Content-Type':'text/html',
            //只允许通过外链加载的js执行
            // 'Content-Security-Policy':'default-src http: https:'

            // 只允许通过外链的从本域加载的js执行
            'Content-Security-Policy':'default-src \'self\''

            //只允许通过外链的从本域或者 http://code.jquery.com/加载的js执行
            // 'Content-Security-Policy':'default-src \'self\' http://code.jquery.com/'
        });
        response.end(html);
    }else{
        response.writeHead(200,{
            'Content-Type':'application/javascript'
        });
        response.end('console.log("loaded script")');
    }

}).listen(8888);

console.log('service listening on 8888');
image.png

Content-Security-Policy的设置可以在服务端,亦可以在客户端返回的html文档。

nginx代理

proxy_cache_path cache levels=1:2 keys_zone=my_cache:10m;

server {
    listen          80;
    server_name     test.com;
    location / {
        proxy_cache my_cache;
        proxy_pass http://127.0.0.1:8888;
        proxy_set_header Host $host;
    }
}

server {
    listen          80;
    server_name     a.test.com;
    location / {
        proxy_pass http://127.0.0.1:8888;
        proxy_set_header Host $host;
    }
}

server {
    listen          80;
    server_name     b.test.com;
    location / {
        http://127.0.0.1:8888 http://127.0.0.1:8888;
        proxy_set_header Host $host;
    }
}

其中server是指要在电脑上起一个服务,其端口是80,它的server_name即域名为test.com,这个server_name指的就是我们在浏览器上面要访问的hostname,nginx会根据要访问的hostname来判断要把服务启动在什么地方,代理到什么地方。比如上面配置了test.com,说明要访问的地址是test.com,然后test.com被代理到的服务是http://127.0.0.1:8888。(要记得在hosts文件中配置test.com的映射地址,如127.0.0.1);之后我们写后端服务。
service.js代码如下

const http = require('http');
const fs = require('fs');

const wait = (seconds)=>{
    return new Promise((resolve,reject)=>{
       setTimeout(()=>{
           resolve();
       },seconds*1000);
    });
};

http.createServer(function (request, response) {
    console.log('request come',request.url);
    const host = request.headers.host;
    /**
     * const html = fs.readFileSync('./test.html','utf-8');
     * 此处不能用utf-8编码,因为utf-8读取时按照字符串读取,使用zlib的话,
     * 希望读取的是buffer
     * */
    const html = fs.readFileSync('./test.html');
    if(request.url==='/'){
        response.writeHead(200,{
            'Content-Type':'text/html',
        });
        response.end(html);
    }
    if(request.url==='/data'){
        /**s-maxage是专门给代理缓存用的,同时使用了max-age=20, s-maxage=20,
         * 那么代理缓存会使用s-maxage,浏览器会使用max-age。
         * **/
        response.writeHead(200,{
            'Cache-Control':'max-age=2;s-maxage=20'
        });
        wait(2).then(()=>{
            response.end('success')
        });
    }
}).listen(8888);

console.log('service listening on 8888');

test.html代码如下

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>nginx-cache</title>
</head>
<body>
    <div>
        <span>this is content, and data is: </span>
        <span id="data"></span>
    </div>
    <script>
        fetch('/data').then(function (resp) {
           return resp.text();
        }).then(function (text) {
            document.getElementById('data').innerText = text;
        })
    </script>
</body>
</html>

test.conf的配置是

proxy_cache_path cache levels=1:2 keys_zone=my_cache:10m;

server {
    listen          80;
    server_name     test.com;
    location / {
        proxy_cache my_cache;
        proxy_pass http://127.0.0.1:8888;
        
    }
}

server {
    listen          80;
    server_name     b.test.com;
    location / {
        proxy_pass http://127.0.0.1:8888;
        proxy_set_header Host $host;
    }
}

从代码中可以看出,在访问'/'路径会返回test.html,在test.html中发起了一个请求,并将结果文本显示到页面上。服务端我们延时了2s去返回请求,并设置了响应头'Cache-Control':'max-age=2, s-maxage=20',告诉浏览器可以缓存结果2秒(max-age=2),告诉代理服务器可以缓存20秒(s-maxage=20)。启用代理服务缓存还需要在具体的server配置 proxy_cache。参照上面的test.conf。
修改service.js ,设置Cache-Control的值为

response.writeHead(200,{
            'Cache-Control':'max-age=5,s-maxage=20,private'
        });

在浏览器端重新刷新,会发现s-maxage=20将不再生效。private是指只有浏览器才可以缓存数据。

HTTPS 即http+secret

加密

image.png
上一篇 下一篇

猜你喜欢

热点阅读