• Access-Control-Allow-Origin 访问-控制-允许-来源
  • CORS Cross-Origin Resource Sharing 跨源资源共享

# CORS预请求

  • 跨域请求的允许方法(get/post/head),其他的方法默认不允许
  • 跨域请求允许的Content-Type(text/plain mulitpart/form-data application/x-www-form-urlencoded)

如果是自定义的请求头,需要配置Access-Control-Allow-Headers

"Access-Control-Allow-Headers":"xx-xxx"

如果要使用其他请求方法需要配置Access-Control-Allow-Methods

"Access-Control-Allow-Methods":"POST,PUT,Delete"

时间方面

"Access-Control-Max-Age":"1000"
const http = new require("http")
http.createServer(function(req,res){
	res.writeHead(200,{
		'Access-Control-Allow-Origin':"*",
		"Access-Control-Allow-Methods":"POST,PUT,Delete",
		"Access-Control-Allow-Headers":"x-1,x-3",
		"Access-Control-Max-Age":"1000"
	})
	res.end('99999')
}).listen(9001,()=>{
	console.log('server is ok')
})  
fetch('http://localhost:9001',{
		method:"PUT",
		headers:{
			'x-1':"123",
			"x-3":'1111'
		}
	})

# 缓存Cache-Control

  • 可缓存性

public private(只有浏览器缓存才有效,代理服务器即使做了缓存也不会生效) no-cache(需要缓存验证) no-store(不缓存,不管有没有设置到期时间,都回去请求数据)

  • 到期
max-age=<seconds>
s-maxage=<seconds>//为代理服务器设置
max-stale
if(req.url==="/s.js"){
		res.writeHead(200,{
			"Content-Type":"text/javascript",
			'Cache-Control':"max-age=20"
		})
		res.end('console.log("apple1")')
	}
  • 重新验证

revalidate:使重新生效;

must-revalidate
proxy-revalidate
  • Last-Modified

上次修改时间,配合If-Modified-Since或者If-Unmodified-Since使用

  • Etag

数据签名,配合If-Match或者If-None -Match使用

if (request.url==='/script.js') {
    const etag=request.headers['if-none-match']

    if (etag==='777') {
      response.writeHead(304,{
        'Content-Type':'text/javascript',
        'Cache-Control':'max-age=30000000,no-cache',
        'Last-Modified':'123',
        'Etag':'777'
      })
      response.end('')  
    }else{
      response.writeHead(200,{
        'Content-Type':'text/javascript',
        'Cache-Control':'max-age=30000000,no-cache',
        'Last-Modified':'123',
        'Etag':'777'
      })
      response.end('console.log("script loaded!")')  
    }


    
  };
res.writeHead(200,{
			'Content-Type':'text/html',
			'Set-cookie':['id=1234;max-age=2','name=sk','sex=0;HttpOnly',"cc=1990;domain=test.com"]
		})

# 长连接

if (request.url==='/') {
    const html=fs.readFileSync('test.html','utf8')
    response.writeHead(200,{
      'Content-Type':'text/html',
      'Set-Cookie':['id=123;max-age=10','abc=456;HttpOnly','test=789;domain=test.com']
    })
    response.end(html)  
  }else{
    response.writeHead(200,{
      'Content-Type':'image/jpg',
      'Connection':'close'
    })
    response.end(img) 
  }

http1.1默认长连接,可以设置connection来决定是否进行长连接,close为关闭,keep-alive也可以设置时长

# 数据协商

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

http.createServer(function(request,response){
    const html=fs.readFileSync('test.html')
    response.writeHead(200,{
      'Content-Type':'text/html',
      'Content-Encoding':'gzip',
      'X-Content-Type-Options':'nosniff'
    })
    response.end(zlib.gzipSync(html))
    // response.writeHead(200,{
    //   'Content-Type':'text/html',
    //   'X-Content-Type-Options':'nosniff'
    // })
    // response.end(html)
}).listen(8888)
console.log('server listening on 8888')

# Redirect

if (request.url==='/') {
      //302:临时跳转(永远都在服务器端做跳转)
      //301:永久跳转(告诉浏览器下次访问直接在浏览器端做跳转,301使用要非常慎重,如果用户不清浏览器缓存会一直跳转)
      response.writeHead(302,{
        'Location':'/new'
      })
      response.end('')  
    };
    if (request.url==='/new') {
      response.writeHead(200,{
        'Content-Type':'text/html',
        'Content-Encoding':'gzip',
        'X-Content-Type-Options':'nosniff'
      })
      response.end(zlib.gzipSync(html))
    };

# Content-Security-Policy

HTTP 响应头 Content-Security-Policy 允许站点管理者控制用户代理能够为指定的页面加载哪些资源。除了少数例外情况,设置的政策主要涉及指定服务器的源和脚本结束点。这将帮助防止跨站脚本攻击(Cross-Site Script)

Content-Security-Policy: <policy-directive>; <policy-directive>
// 部分指令
+ default-src:为其他取指令提供备用服务
+ font-src:设置允许通过 @font-face 加载的字体源地址
+ frame-src:设置允许通过类似 <frame> 和 <iframe> 标签加载的内嵌内容的源地址
+ img-src:限制图片和图标的源地址
+ script-src:限制 JavaScript 的源地址
+ style-src:限制层叠样式表文件源
+ form-action:限制能被用来作为给定上下文的表单提交的目标 URL(说白了,就是限制 form 的 action 属性的链接地址)
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf-8">
        <title></title>
        <!-- 前端页面上设置,加了jquery就访问不了了-->
        <meta http-equiv="Content-Security-Policy" content="form-action 'self';script-src 'self' http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.1.min.js https://unpkg.com/vue@3/dist/vue.global.js ;">
    </head>
    <body>
        <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-2.1.1.min.js"></script>
		<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
        <script type="text/javascript">
            console.log($)
        </script>
		<img src="https://weishell.github.io/img/logo.jpg" alt="">
    </body>
</html>
if (request.url==='/') {
      response.writeHead(200,{
        'Content-Type':'text/html',
        // 'Content-Security-Policy':'default-src http: https:'
        // 'Content-Security-Policy':'default-src \'self\''
        // 'Content-Security-Policy':'default-src \'self\' https://cdn.bootcss.com'
        // 'Content-Security-Policy':'default-src \'self\'; form-action \'self\''
        // 'Content-Security-Policy':'acript-src \'self\'; form-action \'self\';'
        // 'Content-Security-Policy':'acript-src \'self\'; form-action \'self\'; report-uri /report'
        'Content-Security-Policy-Report-Only':'acript-src \'self\'; form-action \'self\'; report-uri /report'
      })
      response.end(html) 
    }

链接 (opens new window)

# 代理服务器使用缓存

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; #nginx对http请求的host进行转发
  }
}

server {
  listen       80;
  server_name  a.test.com;
  location / {
     proxy_pass http://127.0.0.1:8888;
     proxy_set_header Host $host; #nginx对http请求的host进行转发
  }
}

server {
  listen       80;
  server_name  b.test.com;
  location / {
     proxy_pass http://127.0.0.1:8888;
     proxy_set_header Host $host; #nginx对http请求的host进行转发
  }
}
const http=require('http');
const fs=require('fs')
const wait=(second)=>{
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve()
    },second*1000)
  })
}
http.createServer(function(request,response){
  console.log('request come',request.headers.host)
  if (request.url==='/') {
    const html=fs.readFileSync('test.html','utf8')
    response.writeHead(200,{
      'Content-Type':'text/html',
    })
    response.end(html)  
  };
  if (request.url==='/data') {
    response.writeHead(200,{
      'Cache-Control':'s-maxage=200',
      'Vary':'X-Text-Cache'
    })
    wait(2).then(()=>{
      response.end('success')  
    })
  };
}).listen(8888)
console.log('server listening on 8888')
<script type="text/javascript">
  var index=0;
  function doRequest(){
    document.getElementById('data').innerText=''
    fetch('/data',{
      headers:{
        'X-Text-Cache':index++
      }
    }).then((resp)=>{
      return resp.text()
    }).then((text)=>{
      document.getElementById('data').innerText=text
    })  
  }
  document.getElementById('btn').addEventListener('click',doRequest)
</script>

Vary:当设置的值相等时才会使用缓存 ;可以不需要这个参数;s-maxage专为代理服务器配置的缓存时间;

问题

  1. 现代浏览器在与服务器建立了一个 TCP 连接后是否会在一个 HTTP 请求完成后断开?什么情况下会断开?

在 HTTP/1.0 中,一个服务器在发送完一个 HTTP 响应后,会断开 TCP 链接。但是这样每次请求都会重新建立和断开 TCP 连接,代价过大。所以虽然标准中没有设定,某些服务器对 Connection: keep-alive 的 Header 进行了支持。意思是说,完成这个 HTTP 请求之后,不要断开 HTTP 请求使用的 TCP 连接。这样的好处是连接可以被重新使用,之后发送 HTTP 请求的时候不需要重新建立 TCP 连接,以及如果维持连接,那么 SSL 的开销也可以避免.头一次访问,有初始化连接和 SSL 开销。初始化连接和 SSL 开销消失了,说明使用的是同一个 TCP 连接。

持久连接:既然维持 TCP 连接好处这么多,HTTP/1.1 就把 Connection 头写进标准,并且默认开启持久连接,除非请求中写明 Connection: close,那么浏览器和服务器之间是会维持一段时间的 TCP 连接,不会一个请求结束就断掉。

所以第一个问题的答案是:默认情况下建立 TCP 连接不会断开,只有在请求报头中声明 Connection: close 才会在请求完成后关闭连接。

  1. 一个 TCP 连接可以对应几个 HTTP 请求?

如果维持连接,一个 TCP 连接是可以发送多个 HTTP 请求的

  1. 一个 TCP 连接中 HTTP 请求发送可以一起发送么(比如一起发三个请求,再三个响应一起接收)?

HTTP/1.1 存在一个问题,单个 TCP 连接在同一时刻只能处理一个请求,意思是说:两个请求的生命周期不能重叠,任意两个 HTTP 请求从开始到结束的时间在同一个 TCP 连接里不能重叠.在建立起一个 TCP 连接之后,假设客户端在这个连接连续向服务器发送了几个请求。按照标准,服务器应该按照收到请求的顺序返回结果,假设服务器在处理首个请求时花费了大量时间,那么后面所有的请求都需要等着首个请求结束才能响应。但是,HTTP2 提供了 Multiplexing 多路传输特性,可以在一个 TCP 连接中同时完成多个 HTTP 请求。

  1. 为什么有的时候刷新页面不需要重新建立 SSL 连接? TCP 连接有的时候会被浏览器和服务端维持一段时间。TCP 不需要重新建立,SSL 自然也会用之前的。

  2. 浏览器对同一 Host 建立 TCP 连接到数量有没有限制? 有。Chrome 最多允许对同一个 Host 建立六个 TCP 连接。不同的浏览器有一些区别。

最后更新: 5/2/2024, 7:48:09 AM