一、前端跨域
1、概念
1、同源策略及其限制内容
同源策略是一种约定,它是浏览器最核心也是最基本的安全功能,如果少了同源策略,浏览器很容易受到XSS、CSRF等攻击。
同源,指的是“协议 + 域名 + 端口”三者相同(即使两个不同的域名指向同一个IP地址,也不是同源)
2、同源策略的限制内容
1、不能访问对方的Cookie、LocalStorage、indexedDB等存储性内容
2、不能读取和修改对方的DOM节点
3、AJAX请求发送后,结果被浏览器拦截了(限制XMLHttpRequest请求)
但是有三个标签允许跨域加载资源
<img src=""> // 加载图片(比如加载其他网站的图片,不用配置跨域)
<link href="">
<script src="">
3、常见的跨域场景
当协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。
不同域之间互相请求资源,就算作“跨域”
| URL | 说明 | 是否允许通信 |
|---|---|---|
http://www.a.com/a.js与http//www.a.com/b.js |
同一域名下 | 允许 |
http://www.a.com/lab/a.js与http://a.com/script/b.js |
同一域名下不同文件夹 | 允许 |
http://www.a.com:8000/a.js与http://www.a.com:7777/b.js |
同一域名,不同端口 | 不允许 |
http://www.a.com/a.js与https://www.a.com/b.js |
同一域名,不同协议 | 不允许 |
http://www.a.com/a.js与http://www.70.32.92.74/b.js |
域名和域名对应IP | 不允许 |
http://www.a.com/a.js与http://scrpt.a.com/b.js |
主域相同,子域不同 | 不允许 |
http://www.a.com/a.js与http://a.com/b.js |
同一域名,不同二级域名 | 不允许 |
http://www.cnblogs.com/a.js与http://www.a.com/b.js |
不同域名 | 不允许 |
注:如果是协议和端口造成的跨域问题“前台”是无能为力的
4、请求跨域了,请求发出去了没有?
重点:跨域并不是请求发不出去,请求能发出去,服务器能收到请求并正常返回结果,只是结果被浏览器拦截了。
表单可以跨域,而Ajax不能,原因在于跨域是为了阻止用户读取到另外一个域名下的内容,而表单仅是提交内容,不会返回新的内容
2、跨域处理
1、CORS(跨源资源共享)
原理:CORS是浏览器的一种机制,它允许Web应用在请求跨域资源时,服务器通过特定的HTTP头部来允许或拒绝跨域请求
使用:
在服务器端配置响应头,如Access-Control-Allow-Origin,来指定允许的跨域来源
2、JSONP
原理:JSONP是一种通过动态创建script标签来跨域请求数据的技术。它可以绕过浏览器的同源策略。
优点是简单兼容性好,缺点是仅支持get方法。
1、前端定义解析函数
<script>
window.jsonpCallback = function(res) {
console.log(res)
}
</script>
2、通过params形式包装请求参数,并且声明执行函数(cb = jsonpCallback)
<script src="http://localhost:8080/api/jsonp?msg=hello&cb=jsonpCallback"></script>
3、后端获取前端声明的执行函数(jsonpCallback),并以带上参数、调用执行函数的方式传递给前端
//后端代码
const Koa = require("koa")
const app = new Koa()
app.use((ctx, next) => {
cnost { cb, msg } = ctx.query
ctx.body = `${cb}(${JSON.stringify{ msg }})`
return
})
3、代理(proxy)
原理:通过将前端请求代理到同源的后端接口,来绕过跨域问题。这种方式通常在开发环境中使用
//webpack代理配置
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://example.com', // 目标服务器地址
changeOrigin: true, // 修改请求头中的 Origin 字段
pathRewrite: { '^/api': '' }, // 重写路径,例如将 /api 转换为空
secure: false, // 是否验证 SSL
},
},
};
这种方式下,浏览器会向本地 Webpack 开发服务器发送请求(如 http://localhost:3000/api/user),然后 Webpack 开发服务器将请求转发给 http://example.com/api/user,浏览器最终接收到来自目标服务器的响应。
4、Websocket
原理:Websocket协议本身没有同源策略的限制,允许跨域通讯
使用:前端通过Websocket连接到后端服务,进行数据交换
3、预请求
预请求是CORS(跨源资源共享)机制中的一个概念,用于在实际的跨域请求之前,先向服务器发送一个“预检请求”以确认是否允许这次跨域请求。
预请求主要用于复杂请求,以确保请求在服务器上得到正确的处理
流程:当浏览器发起一个跨域请求,如果该请求属于复杂请求(比如使用了某些特定的HTTP方法或自定义的请求头),浏览器会先发送一个OPTIONS请求,这就是预请求。
预请求的条件:
- 使用了非简单请求方法:例如,
PUT、DELETE、PATCH,或某些自定义的方法(例如自定义的X-Requested-With)。 - 使用了自定义请求头:例如,
Authorization、X-Custom-Header等自定义头部。 - 请求中含有特定的内容类型:如
application/json、application/xml等,或者某些特殊的Content-Type。
作用
1、安全性:通过预请求,浏览器可以提前了解服务器是否支持该跨域请求,避免发送可能会被服务器拒绝的实际请求。
2、性能优化:预请求可以避免频繁的无效请求,如果服务器响应预请求时标明允许跨域请求,浏览器会缓存此信息一定时间,从而减少多次发送预请求的开销。
二、host配置
基本作用
host文件是一个没有扩展名的系统文件。
基本作用是将一些常用的网址域名与其对应的IP地址建立一个关联的“数据库”,当用户再浏览器中输入网址时,系统会首先从hosts文件中寻找到对应的IP地址,一旦找到即立刻打开对应网页。如果没有找到,则系统再会将网址提交到DNS域名解析服务器进行IP地址的解析。
优势
1、加快域名解析
对于那些经常要访问的网站,通过再host配置域名与IP的映射关系,从而为浏览器省去请求DNS解析域名的步骤,提高访问速度
2、方便记忆
对于难以记忆的IP地址,但是又需要经常使用,可以通过host配置一个容易记忆的域名
修改方式
windows操作系统:C:\Windows\System32\drivers\etc/hosts
一般直接修改会提示权限不足,需要赋予该文件被修改的权限
三、HTTP缓存
1、 相关字段header
1、Expires
响应头,代表资源的过期时间
2、Cache-Control
请求/响应头,缓存控制字段,精准控制缓存策略
3、If-Modified-Since
请求头,资源最近的修改时间。由浏览器告诉服务器。等于上一次服务器返回的Last-Modified
4、Last-Modified
响应头,资源最近修改时间,由服务器告诉浏览器
5、Etag
响应头,资源标识,有服务器告诉浏览器。理解为资源内容是否被修改的唯一ID
6、if-None-Match
请求头,缓存资源标识,由浏览器告诉服务器。等于上一次服务器返回的Etag
总结:
响应头字段:Expire、Cache-Control、Last-Modified、Etag
请求头字段:Cache-Control、Last-Modified-Since、If-None-Match
搭配使用:
Last-Modified和If-Modified-Since
Etag和If-None-Match
2、 解析缓存机制
假设浏览器向服务器请求index.html资源,其中请求头1KB、响应头1KB、资源文件10KB
1、原型模型
- 浏览器请求静态资源(请求头1KB)
- 服务器读取磁盘文件index.html,返回给浏览器(10KB+1KB响应头 = 11KB)
- 浏览器重复请求,如此循环...
一个往返,总共花费12KB流量。假设访问10次,岂不是花费120KB流量
缺点:浪费用户流量、消耗服务器性能、每次都要重新下载文件影响用户体验
js 执行时间相比下载时间要快的多,如果能优化下载时间,用户体验会提升很多。
2、浏览器增加缓存机制
- 浏览器第一次请求index.html,缓存到本地磁盘(12KB)
- 浏览器再次请求,直接从本地缓存中获取(200状态码),不用向服务器发起请求
优点:大大减少带宽、减少index.html资源下载次数,提高用户体验
缺点:服务器上index.html更新时,浏览器感知不到,拿不到最新的js资源
3、约定资源过期时间
服务器和浏览器约定文件过期时间,用Expire字段控制,时间是GMT格式的标准时间
- 浏览器第一次请求资源(1KB)
- 服务器把index.html和过期时间Expire发送给浏览器(10 + 1KB)
- 浏览器记住了Expire
在Expire之前,浏览器再次发送请求使用缓存就行,不用去找服务器
优势:过期时间Expire内,为用户节省了流量,减轻了服务器压力。过期之后,能够得到最新的index.html
缺点:缓存过期后,服务器不管index.html有没有变化,都会再次读取并返回给浏览器
4、服务器返回资源上次修改时间
注:资源修改时间改变,并不意味着资源内容一定发生了改变
服务器每次返回index.html时,除了返回Expire过期时间,还要返回index.html最近在服务器上的修改时间Last-Modified
- 浏览器访问index.html(1KB)
- 服务器返回index.html,并返回Expire和Last-Modified(10 + 1 = 11KB)
- 当index.html过期后,浏览器带上If-Modified-Since(等于上一次请求的Last-Modified)请求服务器(1KB):
- 两者一致,则说明资源无修改,浏览器继续使用本地缓存(304)
- 不一致,返回index.html + 新的Expire + 新的Last-Modified (11KB)
优点:
检测资源是否修改,没有修直接使用本地缓存,直接省了10KB流量;浏览器总能得到最新的index.html
缺点:
Expire过期时间控制不稳定,因为浏览器端可以随意修改时间,导致缓存使用不精准;
Last-Modified只能进准到秒,如果资源1s内修改了多次,服务器不能准确识别
最重要的是,资源时间修改了,但是资源内容没有改变,浏览器完全可以继续使用缓存
5、使用相对时间控制,Cache-Control
服务器除了告诉浏览器Expires,同时告诉浏览器一个相对时间Cache-Control :max-age = 10秒。意思是10s内,浏览器继续使用本地缓存。
区别:
1、Cache-Control与Expire有相同的功能,但是Cache-Control还有更多的拓展空间,可以实现精准控制
2、如果浏览器同时检测到Cache-Control与Expire,会以Cache-Control为准,忽略Expire
6、增加文件内容对比,引入Etag
前面提到,Last-Modified只是资源文件的修改时间,有时候资源修改时间变化了,但是内容却不一定变化
规则:
在服务器引入Etag,index.html内容变化,Etag变化;内容不变,Etag不变。可以理解成Etag是资源内容唯一的ID。
在浏览器引入If-None-Match,发送请求时带上该字段,值等于上次请求时服务器返回的Etag
- 浏览器第一次请求index.html
- 服务器返回index.html,同时返回绝对过期时间Expire、相对时间Cache-Control :max-age=10,Last-Modified修改时间,Etag内容修改标识
- 10秒钟内,浏览器再次请求,直接使用本地
- 10秒钟后请求,浏览器携带上If-Modified-Since和上次的Etag值 = If-None-Match
- 服务器直接判断If-None-Match和资源的最新Etag,忽略If-Modified-Since(如果没有 If-None-Match字段,则用它)
- If-None-Match === 新的Etag,说明资源无修改,继续使用本地缓存(304)
7、补充
Cache-Control除了可以设置max-age相对过期时间外,还可以设置成如下几种值:
- public,资源允许被中间服务器缓存
- private,资源不允许被中间代理服务器缓存
- no-cache,浏览器不做缓存检查
- no-state,浏览器和中间代理服务器都不能缓存资源
四、http和https
1、http 和 https 的基本概念
http超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少
https是以安全为目标的http通道,简单讲是http的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL(http s的SSL加密是在传输层实现的)
https协议的主要作用是:建立一个信息安全通道,来确保数据的传输,确保网站的真实性。
http协议属于应用层的协议
https
1、对称加密/非对称加密
对称加密:加密和解密的秘钥相同
非对称加密:加密和解密的秘钥不同
创建者创建一个秘钥对(分为公钥和私钥),公钥加密必须私钥解密,私钥加密必须公钥解密。创建者保留私钥,公钥向外界公开
2、http和https的区别
1、https协议需要ca证书,费用较高
2、http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议
3、使用不同的链接方式,端口也不同,http协议默认端口:80,https默认端口:443
4、http的链接很简单,是无状态的;https协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议、比http协议安全
4、http状态码
概述
http状态码(http status code)是用来表示http响应状态的数字代码。http状态码非常多,可以根据不同的情况,给客户端返回不同的状态码
1xx状态码
| 1xx状态码 | 表示目前是协议处理的中间状态,还需要后续操作 |
|---|---|
| 101——Switching Protocols切换协议 | 在HTTP升级为websocket的时候,如果服务器同意变更,就会发送状态码101 |
2xx状态码
| 2XX——Success成功状态码 | 2XX响应的结果表明请求被正常处理了 |
|---|---|
| 200——OK(成功) | 表示从客户端发送的请求在服务器端被正常处理了 |
| 204——No Content 无内容 | 表示服务器接收到请求已成功处理,但是不用返回数据,浏览器不用刷新页面,也不用导向新的页面 |
| 206——Partial Content 部分内容 | 该状态码表示客户端进行了范围请求,而服务器成功执行了这部分的GET请求 |
3xx状态码
| 3XX——Redirection(重定向状态码) | 表明浏览器需要执行某些特殊的处理以正确处理请求 |
|---|---|
| 301——Moved Permanently 永久重定向 | 请求的资源已经永久移动到新位置 |
| 302——Found 临时性重定向 | 资源的URL临时定位到了其他位置,希望用户本次能使用新的URL访问 |
| 303——See other 查看其他位置 | 与302类似,资源的URL已更新。不同在于客户端应当采用GET方法来获取资源 |
| 304——Not Modified 未修改 | 客户端发送附带条件的请求时,服务器端允许访问资源,但未满足条件。(条件指请求报文中包含If-none-Match、If-Modified-Since等) |
注:304虽然被划分在3xx中,但是和重定向没有关系
4xx状态码
表明客户端是发生错误的原因所在
| 4xx——Client Error 客户端错误状态码 | 表明客户端是发生错误的原因所在 |
|---|---|
| 400——Bad Request 错误请求 | 服务器不理解请求的语法 |
| 401——Unauthorized 未授权 | 请求要求身份验证 |
| 403——Forbidden 禁止 | 服务器拒绝请求 |
| 404——Not Found 未找到 | 服务器找不到请求的网页 |
| 405——Method Not Allowed 方法禁用 | 服务器禁止使用该方法 |
5xx状态码
| 5xx_Server Error 服务器错误状态码 | 表明服务器本身发生错误 |
|---|---|
| 500——Internal Server Error 服务器内部错误 | 服务器在执行请求时发生了错误 |
| 502——Bad Gateway 错误网关 | 表明扮演网关或代理角色的服务器,从上游服务器中接收到的响应是无效的 |
| 503——Service Unavailable 服务不可用 | 由于超载或系统维护,服务器暂时的无法处理客户端的请求 |
常见的状态码
| 状态代码 | 状态描述 | 说明 |
|---|---|---|
| 200 | OK | 客户端请求成功 |
| 400 | Bad Request | 客户端请求的语法错误,服务器无法理解 |
| 401 | Unauthorized | 请求要求用户的身份认证 |
| 403 | Forbidden | 服务器收到请求,但是拒绝提供服务 |
| 404 | Not Found | 服务器无法根据客户端的请求找到资源(网页) |
| 500 | internal server error | 服务器内部错误,无法完成请求 |
| 503 | service unavailable | 由于超载或系统维护,服务器暂时的无法处理客户端的请求 |
5、http常见的请求方法
http1.0定义了三种:get、post、head
http1.1新增了五种:options、put、delete、trace、connect
| 方法 | 描述 |
|---|---|
| GET | 请求指定的页面信息,并返回实体主体 |
| POST | 向指定资源提交数据进行处理请求(提交表单、上传文件)。数据被包含在请求体中,post请求可能会导致新的资源建立或者已有资源的修改 |
6、GET和POST的区别
不同
1、基本概念不同
GET-从指定的资源请求数据
POST-向指定的资源提交要被处理的数据
2、get参数通过url传递,post放在request body(请求体中)
3、get请求在url中传递的参数时有长度限制的,而post没有
4、get比post更不安全,因为参数直接暴露在url中,不能用来传递敏感信息
5、get请求只能进行url编码,而post支持多种编码方式
6、get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留
7、get产生一个TCP数据包;post产生两个tcp数据包
对于get方式的请求,浏览器会把http、header和data一并发送出去,服务器响应200(返回数据);
对于post,浏览器先发送header,服务器响应100 continue,浏览器字啊发送data,服务器响应200 ok(返回数据)
相同
GET和POST的底层都是TCP/IP,GET/POST都是TCP链接
7、http常见请求头
客户端发送一个http请求到服务器的请求消息包括一下格式:请求行(request line)、请求头部(header)、空行和请求数据
| 请求头 | 说明 |
|---|---|
Host |
发送请求时,该头域是必需的。主要用于指定被请求资源的Internet主机和端口,它通常从HTTP URL中提取出来的 |
Accept |
浏览器可接受的MIME类型。例如:Accept:text/html代表浏览器可以接受服务器回发的类型为text/html,即HTML文档;Accept:* / * 代表浏览器可以处理所有类型 |
Accept-Encoding |
浏览器能够进行解码的数据编码方式。通常指定压缩方法,是否支持压缩,支持什么压缩方法(gzip、deflate)。注:如果请求消息中没有设置这个域,服务器假定客户端对各种内容编码都可以接受 |
Accept-Charset |
浏览器可接受的字符集。注:请求消息中没有设置这个域,表示任何字符集都可以接受 |
Accept-Language |
浏览器申明自己接收的语言。注:语言跟字符集的区别:中文是语言,中文有很多字符集(gbk、gb2312等)。例如:Accept-Language:en-us |
User-Agent |
告知http服务器,客户端使用的操作系统和浏览器的名称和版本 |
Content-Length |
表示请求信息正文的长度 |
Referer |
包含一个URL,用户从该URL代表的页面触发访问当前请求的页面 |
Cookie |
最重要的请求头之一,将cookie的值发送给HTTP服务器 |
Connection |
connettion:keep-alive表示当一个页面打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,如果客户端再次访问这个服务器上的网页,会继续使用这一条已经建立的连接 |
Authorization |
授权信息,通过出现在对服务器发送的WWW-Authenticate头应答中。主要用于证明客户端有权查看某个资源。当浏览器访问一个页面时,如果收到服务器的响应代码401,可以发送一个包含Authorization请求报文域的请求,要求服务器对其进行验证 |
8、http常见响应头
HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文
| 应答头 | 说明 |
|---|---|
| Allow | 服务器支持哪些请求方法(如GET、POST等)。 |
| Content-Encoding | 文档的编码(Encode)方法。只有在解码之后才可以得到Content-Type头指定的内容类型。利用gzip压缩文档能够显著地减少HTML文档的下载时间。Java的GZIPOutputStream可以很方便地进行gzip压缩,但只有Unix上的Netscape和Windows上的IE 4、IE 5才支持它。因此,Servlet应该通过查看Accept-Encoding头(即request.getHeader("Accept-Encoding"))检查浏览器是否支持gzip,为支持gzip的浏览器返回经gzip压缩的HTML页面,为其他浏览器返回普通页面。 |
| Content-Length | 表示内容长度。只有当浏览器使用持久HTTP连接时才需要这个数据。如果你想要利用持久连接的优势,可以把输出文档写入 ByteArrayOutputStream,完成后查看其大小,然后把该值放入Content-Length头,最后通过byteArrayStream.writeTo(response.getOutputStream()发送内容。 |
| Content-Type | 表示后面的文档属于什么MIME类型。Servlet默认为text/plain,但通常需要显式地指定为text/html。由于经常要设置Content-Type,因此HttpServletResponse提供了一个专用的方法setContentType。 |
| Date | 当前的GMT时间。你可以用setDateHeader来设置这个头以避免转换时间格式的麻烦。 |
| Expires | 应该在什么时候认为文档已经过期,从而不再缓存它? |
| Last-Modified | 文档的最后改动时间。客户可以通过If-Modified-Since请求头提供一个日期,该请求将被视为一个条件GET,只有改动时间迟于指定时间的文档才会返回,否则返回一个304(Not Modified)状态。Last-Modified也可用setDateHeader方法来设置。 |
| Location | 表示客户应当到哪里去提取文档。Location通常不是直接设置的,而是通过HttpServletResponse的sendRedirect方法,该方法同时设置状态代码为302。 |
| Refresh | 表示浏览器应该在多少时间之后刷新文档,以秒计。除了刷新当前文档之外,你还可以通过setHeader("Refresh", "5; URL=http://host/path")让浏览器读取指定的页面。 注意这种功能通常是通过设置HTML页面HEAD区的<META HTTP-EQUIV="Refresh" CONTENT="5;URL=http://host/path">实现,这是因为,自动刷新或重定向对于那些不能使用CGI或Servlet的HTML编写者十分重要。但是,对于Servlet来说,直接设置Refresh头更加方便。 注意Refresh的意义是"N秒之后刷新本页面或访问指定页面",而不是"每隔N秒刷新本页面或访问指定页面"。因此,连续刷新要求每次都发送一个Refresh头,而发送204状态代码则可以阻止浏览器继续刷新,不管是使用Refresh头还是<META HTTP-EQUIV="Refresh" ...>。 注意Refresh头不属于HTTP 1.1正式规范的一部分,而是一个扩展,但Netscape和IE都支持它。 |
| Server | 服务器名字。Servlet一般不设置这个值,而是由Web服务器自己设置。 |
| Set-Cookie | 设置和页面关联的Cookie。Servlet不应使用response.setHeader("Set-Cookie", ...),而是应使用HttpServletResponse提供的专用方法addCookie。参见下文有关Cookie设置的讨论。 |
| WWW-Authenticate | 客户应该在Authorization头中提供什么类型的授权信息?在包含401(Unauthorized)状态行的应答中这个头是必需的。例如,response.setHeader("WWW-Authenticate", "BASIC realm=\"executives\"")。 注意Servlet一般不进行这方面的处理,而是让Web服务器的专门机制来控制受密码保护页面的访问(例如.htaccess)。 |
9、HTTP1.0/2.0
HTTP1和HTTP2的区别主要体现在性能优化和传输效率上
1、多路复用
HTTP1:每个请求和相应都需要建立独立的连接。即使是同一个页面中的多个资源(如图片、CSS、JS等),也会在多个连接中顺序传输。这样会导致“队头阻塞”(Head-of-line Blocking)问题,尤其是在网络延迟较高时。
HTTP2:支持多路复用,在一个连接中可以同时处理多个请求和响应,不需要为每个资源都建立一个新的连接。
2、请求和相应的头部压缩
HTTP1:请求和响应头部是明文传输的,每个请求都会重复发送相同的头部信息(例如Cookie),浪费带宽
HTTP2:使用HPACK算法进行头部压缩,可以大大减少头部数据的冗余,降低带宽占用
3、服务器推送
HTTP1:没有服务器推送的功能,服务器只能相应客户端的请求,不能主动推送数据
HTTP2:支持服务器推送
4、流控制和优先级
HTTP1:没有流控制和优先级机制,资源的加载顺序无法灵活调整
HTTP2:支持流控制,可以为每个请求设置优先级,确保更重要的资源优先加载,优化了资源的传输顺序
10、HTTP2.0/3.0
HTTP2.0
特点
1、多个请求多路复用
HTTP1.1排队问题:假设有三个文件要发送,会被整合成一条数据发送,也就是说只需要握手三次,而非九次
2、防止队头阻塞
3、压缩HTTP头部
HPACK技术:例如将methods:GET用2来表示,status:200用8表示,节省了很多字符
4、服务端推送
HTTP3.0
HTTP3.0使用了UDP来作为传输协议,其中利用QUIC来保证可靠性、安全性
五、Cookie
1、简介
Cookie本质上就是浏览器里存储的一个很小的文本文件,内部以建立键值对的方式来存储信息。
- HTTP是无状态的协议,每次http请求都是独立、无关的,默认不需要保留状态。服务器无法确认当前访问者的身份信息。所以服务器与浏览器为了进行会话跟踪(知道谁在访问我),就必须主动去维护一个状态,这个状态用于告知服务端前后两个请求是否来自同一个浏览器
- cookie存储在客户端:cookie是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带发送到服务器上
- cookie是不可跨域的:每个cookie都会绑定单一的域名,无法在别的域名下获取使用
2、cookie的属性
| 属性 | 说明 |
|---|---|
| name=value | 键值对,设置 Cookie 的名称及相对应的值,都必须是字符串类型 - 如果值为 Unicode 字符,需要为字符编码。 - 如果值为二进制数据,则需要使用 BASE64 编码。 |
| domain | 指定 cookie 所属域名,默认是当前域名 |
| path | 指定 cookie 在哪个路径(路由)下生效,默认是 '/'。 如果设置为 /abc,则只有 /abc 下的路由可以访问到该 cookie,如:/abc/read。 |
| maxAge | cookie 失效的时间,单位秒。如果为整数,则该 cookie 在 maxAge 秒后失效。如果为负数,该 cookie 为临时 cookie ,关闭浏览器即失效,浏览器也不会以任何形式保存该 cookie 。如果为 0,表示删除该 cookie 。默认为 -1。 - 比 expires 好用。 |
| expires | 过期时间,在设置的某个时间点后该 cookie 就会失效。 一般浏览器的 cookie 都是默认储存的,当关闭浏览器结束这个会话的时候,这个 cookie 也就会被删除 |
| secure | 该 cookie 是否仅被使用安全协议传输。安全协议有 HTTPS,SSL等,在网络上传输数据之前先将数据加密。默认为false。 当 secure 值为 true 时,cookie 在 HTTP 中是无效,在 HTTPS 中才有效。 |
| httpOnly | 如果给某个 cookie 设置了 httpOnly 属性,则无法通过 JS 脚本 读取到该 cookie 的信息,但还是能通过 Application 中手动修改 cookie,所以只是在一定程度上可以防止 XSS 攻击,不是绝对的安全 |
3、cookie缺点
1、容量缺陷。cookie的体积上限只有4KB,只能用来存储少量信息
2、性能缺陷。每次请求都携带上完整的Cookie,随着请求数增多,会造成巨大的性能浪费
3、安全缺陷。由于Cookie以纯文本的形式在浏览器和服务器中传递,很容易被非法用户截获。在HttpOnly为false的情况下,Cookie信息能直接通过JS脚本读取
//读取浏览器中的cookie
console.log(document.cookie)
//写入cookie
document.cookie = 'myname=linming;'
4、Cookie和Session的区别
安全性:Session比Cookie安全,Session是存储在服务器端的,Cookie是存储在客户端的
存取值的类型不同:Cookie只支持字符串数据,想要设置其他类型的数据,需要将其转换成字符串,Seesion可以存任意数据类型
有效期不同:Cookie可以设置为长时间保持,Session一般失效时间较短,客户端关闭或者Session超时都会失效
存储大小不同: 单个Cookie保存的数据不能超过4K,Session可存储数据远高于Cookie,但是访问量过多时,会占用很多的服务器资源
5、简单demo
const koa = require('koa')
const Router = require('koa-router')
const app = new koa()
const useRouter = new Router({ prefix: '/test' })
useRouter.get('/', (ctx, next) => {
ctx.cookies.set("name", "linming", {
maxAge: 60 * 1000
})
ctx.body = "hello world";
})
app.use(useRouter.routes())
app.listen('8080', () => {
console.log("服务器启动成功~");
})
6、单点登录sso
模拟cookie设置过程
const express = require("express");
const app = express();
//真实情况应是post请求
app.get("/login", (req, res) => {
res.setHeader("Set-Cookie", "name=linming");
res.send("ok");
});
app.listen(3000, () => {
console.log("服务器启动成功");
});
登录成功后,服务器给浏览器返回了一个响应头Set-Cookie,浏览器接收到了之后就会将其设置进cookie中
问题:当访问不同源的资源时,存在跨域问题
const express = require("express");
const app2 = express();
app2.get("/info", (req, res) => {
res.send("info");
});
app2.listen(3001, () => {
console.log("服务器2启动成功");
});
当我们在3000端口这个域下访问3001时,就会报跨域问题
fetch("http://127.0.0.1:3001/info", {credentials: 'include'})
解决
app2.get("/info", (req, res) => {
res.send("info");
});
