某生物科技公司
1.代码实现删除一个 list 里面的重复元素
方法1:最简单容易的方法
此方法基于遍历整个列表,将第一个元素添加到新列表中。
# Python 3 code to demonstrate
# removing duplicated from list
# using naive methods
# initializing list
test_list = [1, 3, 5, 6, 3, 5, 6, 1]
print ("The original list is : " + str(test_list))
# using naive method to remove duplicated from list
res = []
for i in test_list:
if i not in res:
res.append(i)
# printing list after removal
print ("The list after removing duplicates : " + str(res))
输出结果:
原始列表是:[1, 3, 5, 6, 3, 5, 6, 1]
删除重复项后的列表:[1, 3, 5, 6]
方法2:理解列表
这个方法其实是第一种方法的简化版,它使用了列表推导式,可以用一行代码代替上面的循环方法。
def remove_duplicates(lst):
return [x for i, x in enumerate(lst) if x not in lst[:i]]
方法3:使用 set()
这是从列表中删除重复元素的最流行的方法。但是,这种方法最大的缺点之一是set后列表中元素的顺序不再和原来一样。
# Python 3 code to demonstrate
# removing duplicated from list
# using set()
# initializing list
test_list = [1, 5, 3, 6, 3, 5, 6, 1]
print ("The original list is : " + str(test_list))
# using set()to remove duplicated from list
test_list = list(set(test_list))
# printing list after removal
# distorted ordering
print ("The list after removing duplicates : " + str(test_list))
输出结果:
原始列表是:[1, 5, 3, 6, 3, 5, 6, 1]
删除重复项后的列表:[1, 3, 5, 6]
方法 4:使用列表理解 + enumerate()
此方法使用枚举根据列表理解删除重复元素。通过检查该元素是否已存在于列表中来跳过该元素。此方法保持列表中元素的顺序。
示例代码:
# Python 3 code to demonstrate
# removing duplicated from list
# using list comprehension + enumerate()
# initializing list
test_list = [1, 5, 3, 6, 3, 5, 6, 1]
print ("The original list is : " + str(test_list))
# using list comprehension + enumerate()
# to remove duplicated from list
res = [i for n, i in enumerate(test_list) if i not in test_list[:n]]
# printing list after removal
print ("The list after removing duplicates : " + str(res))
方法 5:使用 collections.OrderedDict.fromkeys()
这是完成特殊任务的最快方式。它首先删除列表中的重复项并返回一个字典,最后将其转换为列表。此方法也可用于字符串,之后列表中元素的顺序也发生了变化。
# Python 3 code to demonstrate
# removing duplicated from list
# using collections.OrderedDict.fromkeys()
from collections import OrderedDict
# initializing list
test_list = [1, 5, 3, 6, 3, 5, 6, 1]
print ("The original list is : " + str(test_list))
# using collections.OrderedDict.fromkeys()
# to remove duplicated from list
res = list(OrderedDict.fromkeys(test_list))
# printing list after removal
print ("The list after removing duplicates : " + str(res))
2.如何知道一个 python 对象的类型
1、使用type
tyep(123) 直接给出所属的类型
2、isinstance 可以检查一个对象是否为某种类型,或者某个类型的子类
用法:isinstance([],list)
isinstance(2,int)
3、检查对象的__class__属性
每个对象都有一个__class__属性指向创建它的类
>>> 1.__class__
<class 'int'>
3.用 re 匹配文本的时候,<,*>和<,*?>有什么区别?
在Python中使用正则表达式匹配HTML标签时,`<.*>`和`<.*?>`的区别主要体现在匹配的贪婪(greedy)与非贪婪(non-greedy)模式上。贪婪模式会尽可能多地匹配字符,而非贪婪模式会尽可能少地匹配字符。
### 贪婪模式 `<.*>`
- `<.*>` 是贪婪匹配,它会尽可能多地匹配字符。
- 在HTML中,如果你有嵌套的标签,贪婪匹配可能会匹配到最外层的结束标签,而不是你期望的第一个结束标签。
#### 示例
假设你有以下HTML字符串:
```html
"<div><p>Example</p></div>"
```
使用贪婪匹配 `<.*>`:```python
import re
html = "<div><p>Example</p></div>"
pattern = r"<.*>"
matches = re.findall(pattern, html)
print(matches)
输出:
```python
['<div><p>Example</p></div>']
```
可以看到,它匹配了整个字符串,因为贪婪匹配会尽可能多地匹配字符。
### 非贪婪模式 `<.*?>`
- `<.*?>` 是非贪婪匹配,它会尽可能少地匹配字符。
- 在HTML中,这意味着它会匹配到最早的结束标签。
#### 示例
同样的HTML字符串:
"<div><p>Example</p></div>"
使用非贪婪匹配 `<.*?>`:```python
import re
html = "<div><p>Example</p></div>"
pattern = r"<.*?>"
matches = re.findall(pattern, html)
print(matches)
输出:
```python
['<div>', '<p>', '</p>', '</div>']
```
可以看到,非贪婪匹配会匹配到最早的结束标签,因此它匹配到了每个单独的标签。
### 结论
- `<.*>` 会贪婪地匹配,可能会导致匹配结果过多。
- `<.*?>` 会非贪婪地匹配,通常在处理嵌套标签时更合适。
在处理HTML或XML时,使用非贪婪匹配通常会得到更准确的结果,但需要注意的是,正则表达式在处理复杂的HTML或XML结构时并不是最佳选择,使用专门的解析器如BeautifulSoup或lxml会更加可靠和方便。
4.什么是 PEP8
PEP8是Python Enhancement Proposal 8的缩写,它是Python编程语言中的一项官方建议。PEP8规定了Python代码的编写风格和规范,旨在提高代码的可读性和可维护性。
PEP8涵盖了很多方面,包括代码布局、命名约定、注释风格、导入语句等。下面是一些PEP8的主要指导原则:
1.缩进:使用四个空格进行缩进,而不是制表符。
2.行长度:每行代码不应超过79个字符,可以使用括号或反斜杠换行。
3.空格:在运算符和逗号周围加上空格,但不要在括号内加空格。
4.命名规范:变量和函数名应使用小写字母,多个单词之间用下划线分隔(snake_case);类名应使用驼峰命名法(CamelCase)。
5.注释:使用清晰的注释来解释代码的意图和功能。
6.导入语句:每个导入应位于独立的行上,按照标准库模块、第三方库模块和本地模块的顺序导入,每个部分之间应留有空行。
PEP8的目标是使Python代码具有一致的风格,从而提高代码的可读性,并使不同开发者之间的代码更易于理解和协作。符合PEP8规范的代码更易于维护和修改,并且能够与其他遵循PEP8的代码库更好地集成。
5.Django里的MTV架构是什么?
MVC介绍
MVC
全拼为Model-View-Controller
MVC
核心思想 : 解耦- 让不同的模块之间降低耦合, 增强代码的可扩展性和可移植性, 实现更好的向后续版本的兼容
- 开发原则 : 高内聚, 低耦合
MVC
解析M
全拼为Model
, 主要封装对数据库层的访问, 内嵌ORM框架, 实现面向对象的编程来操作数据库.V
全拼为View
, 用于封装结果, 内嵌了模板引擎, 实现动态展示数据.C
全拼为Controller
, 用于接收GET或POST请求, 处理业务逻辑, 与Model和View交互, 返回结果.
- 当前主流的开发语言如
Java、PHP、Python、...
中都有MVC
设计模式
MVT介绍
MVT
全拼为Model-View-Template
MVT
核心思想 : 解耦MVT
解析M (模型)
全拼为Model
, 与MVC中的M功能相同, 负责数据处理, 内嵌了ORM框架.V (视图)
全拼为View
, 与MVC中的C功能相同, 接收HttpRequest, 业务处理,返回HttpResponse.T (模板)
全拼为Template
, 与MVC中的V功能相同, 负责封装构造要返回的html, 内嵌了模板引擎.
MVT和MVC
差异就在于黑箭头标识出来的部分.
6.queryset F 和Q的作用
Django的对象关系映射系统(Object-Relational Mapper, ORM)提供了丰富的数据查询接口, 让你无需使用原生SQL语句即可通过对模型的简单操作实现对数据库里的数据进行增删改查。查询得到的结果叫查询集(QuerySet), 所以这个接口被称为QuerySet API。
from .models import Article
article = Article(title="My first article", body="My first article body")
article.save()
7.contenttypes 是什么?通常我们用来解决什么问题?
contenttypes 是Django内置的一个应用, 可以追踪项目中所有app和model的对应关系,并记录在ContentType表中 。
8.谈谈 RESTful 和 Django REST framework
RESTful
RESTful(Representational State Transfer)是一种架构风格或设计原则,用于构建可扩展和易于维护的 Web 服务。它有以下几个关键特性:
-
资源:RESTful API 将数据和功能视为资源。每个资源由一个唯一的 URI(Uniform Resource Identifier)标识。
-
HTTP 动词:使用标准的 HTTP 动词来操作资源,例如 GET(读取),POST(创建),PUT(更新),DELETE(删除)。
-
无状态:每个请求都是独立的,服务器不保存客户端的状态。客户端每次请求时必须包含所有必要的信息。
-
表现层状态转化(HATEOAS):响应中包含指向相关资源的链接,允许客户端通过链接进行导航。
-
统一接口:通过一致的接口进行交互,简化了客户端和服务器之间的通信。
Django REST framework (DRF)
Django REST framework 是一个强大且灵活的工具包,用于构建 Web API,它是基于 Django 框架构建的。它提供了一些特性,使得构建 RESTful API 更加容易和高效。以下是 Django REST framework 的一些关键特性:
-
视图集和路由:提供了视图集和路由功能,可以轻松地将模型的所有 CRUD 操作映射到 URL。
-
序列化:提供了强大的序列化工具,可以将复杂的 Django 查询集和模型实例转换为 JSON 格式,反之亦然。
-
认证和权限:内置了多种认证和权限机制,例如 Token 认证、OAuth、权限类等。
-
浏览器可浏览 API:提供了一个 Web 浏览器界面,可以直接在浏览器中测试 API,方便开发和调试。
-
自定义视图和路由:允许开发者自定义视图和路由,以满足特定需求。
-
支持多种渲染和解析:支持多种内容类型的渲染和解析,包括 JSON、XML 等。
-
节流(Throttle)和过滤:提供了请求节流和过滤功能,方便管理 API 流量和数据访问。
总结
-
RESTful 是一种架构风格和设计原则,指导如何设计和实现 API,使其具有可扩展性、易维护性和一致性。
-
Django REST framework 是一个框架和工具包,帮助开发者在 Django 中快速、轻松地构建 RESTful API。它实现了 RESTful 架构风格的许多原则和最佳实践。
9.什么是redis,有什么用,一般的使用场景是什么?
9.5 谈谈MYSQL?
mysql是一个关系型数据库,是建立在关系模型基础上,由多张相互连接的二维表相组成,
而二维表指的是由行和列组成的表,类似于excel表格
,简单来说,基于二维表存储数据的数据库就变成关系型数据库,不是基于二维表存储数据的数据库就是非关系型数据库。
特点:使用表存储结构,格式统一,便于维护。
使用sql(结构化查询语言)操作,标准统一,使用方便。
mysql的基础结构图是分为四层、连接层、服务层、引擎层、存储层。
连接层的话,这部分管理连接,权限验证。
第二层是服务层,这一层主要完成大多数的核心服务功能:编写sql接口并完成缓存的查询(如果缓存有数据则直接从缓存提取数据),sql的分析和优化包括分析器(词法分析、语法分析)、优化器(执行计划生成,索引选择)所有跨存储引擎的功能也在这层实现,比如函数、过程等。
第3层是引擎层,负责mysql中数据的存储和提取,服务器通过api和存储引擎进行交互,不同的存储引擎有不同的作用。我们可以根据自己的需要来选取合适的存储引擎。
第4层是存储层,指的是系统的文件系统与存储引擎完成交互并存储数据在上面。
存储引擎就是存储数据、建立索引、更新/查询数据等的技术,存储引擎是基于表的
mysql的常用存储引擎是InnoDB和MyISam,
默认的存储引擎是InnoDB,InnoDB的特点是支持事务、使用行级锁提高并发性能、支持外键保证数据的完整性和可靠性。文件,使用后缀idb存储该表的结构、数据和索引
其次是MyISam,MyISam是早期的默认存储引擎。
特点:不支持事务,不支持外键、不支持行锁。
访问速度快、使用三个文件分别存储结构、数据和索引。
10.请说一些单元测试的了解
11.你在项目的时候有遇到什么困难或者印象深刻的东西
龙象文化传播有限公司
1、前后端怎么处理重复数据提交
后端处理:
-
使用唯一标识符和幂等操作:
-
后端在处理提交数据时,可以要求前端提供一个唯一的标识符(例如请求ID或者时间戳等),并在处理请求时检查该标识符的唯一性。如果已经处理过相同标识符的请求,后端可以忽略或者返回相同的响应。这种方式称为幂等操作。
-
-
数据库唯一约束:
-
在数据库层面设置唯一约束,确保某些字段或者组合字段的数值在数据库中唯一。这样即使前端重复提交了相同数据,数据库也不会接受重复的数据。
-
-
Token机制:
-
使用令牌(Token)来防止重复提交。后端在处理第一次请求时生成一个唯一的Token,并将其返回给前端。前端在后续的请求中携带该Token,后端在接收到请求时检查Token的有效性,以确定是否是重复提交。
-
-
设置请求过期时间:
-
在处理请求时,可以设置一个有效期限制,超过有效期的重复请求将被拒绝。
-
前端处理:
-
禁用提交按钮:
-
在第一次提交后,立即禁用提交按钮,避免用户多次点击。
-
-
显示加载状态:
-
在提交过程中显示加载状态或者进度条,告知用户当前请求正在处理中。
-
-
防抖动(Debouncing):
-
在用户频繁操作时,可以使用防抖动技术,确保只有最后一次操作会真正触发提交。
-
-
前端校验:
-
在前端进行一些基本的数据校验,确保无效的数据不会提交给后端。
-
-
提交确认:
-
在提交前弹出确认框,确保用户意识到他们的操作将要提交数据。
-
综合处理:
-
综合利用前后端的多种手段来处理重复提交问题,可以提高系统的稳定性和用户体验。通常情况下,前端和后端都应该考虑处理重复提交问题,以保证系统数据的一致性和安全性。
2、redis的使用场景
缓存(Cache)
Redis的第一个应用场景是Redis作为缓存对象来加速Web应用的访问。
在该场景下,有一些存储于数据库中的数据会被频繁访问,如果频繁的访问数据库,数据库负载会升高,同时由于数据库IO比较慢,应用程序的响应会比较差。此时,如果引入Redis来存储这些被频繁访问的数据,就可以有效的降低数据库的负载,同时提高应用程序的请求响应。
会话存储(Session)
使用Redis来存储会话(Session)数据,可以实现在无状态的服务器之间共享用户相关的状态数据数据。
当用户登录Web应用时候,将会话数据存储于Redis,并将唯一的会话ID(Session ID)返回到客户端的Cookie中。当用户再向应用发送请求时,会将此会话ID包含在请求中。无状态的Web服务器,根据这个会话ID从Redis中搜索相关的会话数据来进一步请求处理。
这里需要注意的是,Redis是内存数据库,如果采用单实例部署。那么当Redis服务器故障重启之后,所有的Session会话会消失,用户不得不重新登录来获取新的Session。所以,当拿Redis来存储Session的时候,建议采用主从的集群模式来部署。这样,即使主服务器挂了,马上有从库接管流量,不影响用户的使用。
分布式锁(Distributed Lock)
当我们在应用中部署了多个节点,这些节点需要操作同一个资源的时候会存在竞争。此时,我们可以使用Redis来作为分布式锁,以协调多个节点对共享资源的操作。
这里主要是用Redis的原子操作命令:SETNX
,该命令仅允许key不存在的时候才能设置key。
下图展示了一个简单用例。Client 1通过SETNX
命令尝试创建lock 1234abcd
。如果当前还没有这个key,那么将返回1。Client 1获得锁,就可以执行对共享资源的操作,操作完成之后,删除刚刚创建的lock(释放分布式锁)。如果Client 1在执行SETNX
命令的时候,返回了0,说明有其他客户端占用了这key,那么等待一段时间(等其他节点释放)之后再尝试。
上面这个简单实现虽然可以满足很多用例,但它并不具备良好的容错机制。如果要在生产上是用的话,更推荐采用一些更高质量的分布式锁实现。比如,Java平台的话,可以选择:Redisson.
速率限制器(Rate Limiter)
由于Redis提供了计数器功能,所以我们可以通过该能力,配合超时时间,来实现速率限制器,最常见的场景就是服务端是用的请求限流。
一个基本的限速实现如下图:
根据用户id或者ip来作为key,使用INCR
命令来记录用户的请求数量。然后将该请求数量与允许的请求上限数量做比较,只有低于限制的时候,才会执行请求处理。如果超过限制,就拒绝请求。
同时,请求数量的计数器需要设置一个时间窗口,比如:1分钟。也就是没过一分钟时间,计数器将被清零,重新计数。所以,当一个时间窗口中被限流之后,等到下一个时间窗口,就能恢复继续请求。以实现限制速率的效果。
除了时间窗算法之外,漏桶算法也能通过Redis来实现。
排行榜(Rank/Leaderboard)
由于Redis提供了排序集合(Sorted Sets)的功能,所以很多游戏应用采用Redis来实现各种排行榜功能。
排序集合是唯一元素(比如:用户id)的集合,每个元素按分数排序,这样可以快速的按分数来检索元素
小结
Redis的应用非常广泛,这里仅总结了一些常见的用法。除此之外,还有很多有意思的应用,这取决于业务场景。大家可以举一反三。
悦谦科技
1、谈谈rpc和http
HTTP协议(Hyper Text Transfer Protocol)超文本传输协议:
一个用于在网络上交换信息的标准协议,它定义了客户端(例如浏览器)和服务器之间的通信方式。如平时上网在浏览器上敲个网址url就能访问网页,这里用到的就是HTTP协议。
明确 HTTP 是一个协议,是一个超文本传输协议,不是运输通道。它基于 TCP/IP 来传输文本、图片、视频、音频等。HTTP 不提供数据包的传输功能,也就是数据包从浏览器到服务端再来回的传输和HTTP没关系。
HTTP最早版本在1989年提出,经过多年发展,到1996年发布的HTTP/1.1版本一直沿用至今,而在2015年也出现了HTTP/2.0。
RPC(Remote Procedure Call)远程过程调用:
能够调用位于另一个地址空间(通常是网络上的另一台计算机)中的函数,而对程序员来说是透明的。仅仅是远程调用,还不算是RPC,因为RPC强调的是过程调用,调用的过程对用户而言是应该是透明的,用户不应该关心调用的细节,可以像调用本地服务一样调用远程服务。所以RPC一定要对调用的过程进行封装。
它本身并不是一个具体的协议,只是一种协议的规范,明确的说是概念、机制或者思想,它并没有具体实现,只有按照RPC通信协议规范实现的通信框架,也就是RPC框架,才是协议的具体实现,比如Dubbo、gRPC等。它包括了:接口规范+序列化反序列化规范+通信协议等
参考链接 RPC与HTTP基本介绍、历史追溯、主流应用场景、对比分析、为什么还需要使用RPChttps://blog.csdn.net/qq_45808700/article/details/131664118/
2、tcp的连接方式
1. TCP简介
TCP协议广泛应用于可靠性要求较高的应用场景,如网页浏览、文件传输、电子邮件等。它提供了可靠的数据传输和流控制机制,能够确保数据的完整性和有序性。然而,由于TCP协议在传输过程中引入了较多的控制信息,因此相比于UDP协议,TCP的传输速度较慢。
2. TCP和UDP的区别
TCP UDP
有连接 无连接
可靠传输 不可靠传输
面向字节流 面向数据报
全双工 全双工
是否连接: 可以想象成打电话,比如A给B打电话,只有建立好连接才能通信(交换数据),这种是有连接.而是用微信发消息,不需要建立连接则是无连接
是否可靠传输: 这里的可靠,并不是指A给B的数据一定完全能让B收到,只能确保B是不是收到了
字节流和数据报: TCP和文件IO一样基于 “流”,UDP则是以"数据报"为基本单位
全双工: 一个通道,双向通信
参考链接:https://blog.csdn.net/m0_63463510/article/details/132164808
3、内存IO、网络IO、硬盘IO和CPU io的速度
它们的速度排序通常是:CPU IO > 内存IO > 硬盘IO > 网络IO。以下是对每种IO类型的详细解释和速度排序原因:
-
CPU IO
- 定义:CPU IO指的是中央处理器(CPU)与其内部组件(如寄存器和缓存)之间的数据传输。
- 速度:最快,因为数据传输在CPU内部进行,不涉及外部硬件。CPU内部的寄存器和缓存的访问时间通常在纳秒级(ns)。
- 示例:CPU从寄存器读取数据或将数据写入寄存器。
-
内存IO
- 定义:内存IO指的是CPU与主内存(RAM)之间的数据传输。
- 速度:较快,但比CPU IO慢。内存访问时间通常在几十纳秒到几百纳秒之间,取决于内存类型(如DDR4、DDR5等)和系统架构。
- 示例:CPU从RAM读取数据或将数据写入RAM。
-
硬盘IO
- 定义:硬盘IO指的是数据在存储设备(如HDD或SSD)与内存之间的传输。
- 速度:相比内存IO慢得多。传统机械硬盘(HDD)的访问时间通常在几毫秒(ms),而固态硬盘(SSD)的访问时间可以在微秒(μs)到几毫秒之间。
- 示例:从硬盘读取文件到内存或将数据从内存写入硬盘。
-
网络IO
- 定义:网络IO指的是通过网络接口进行的数据传输,涉及计算机之间或计算机与服务器之间的数据交换。
- 速度:最慢,因为涉及网络延迟、带宽限制和数据包传输。局域网(LAN)内的网络IO可能在微秒到毫秒级,而广域网(WAN)或互联网的网络IO可能在几十毫秒甚至更高。
- 示例:下载文件、发送电子邮件或通过网络进行数据通信。
速度排序总结
- CPU IO:纳秒级(最快)
- 内存IO:几十纳秒到几百纳秒
- 硬盘IO:
- SSD:微秒到几毫秒
- HDD:几毫秒
- 网络IO:微秒到几十毫秒或更高(最慢)
2、vue3的插槽是什么?
Vue 组件通过插槽的方式实现内容的分法,它允许我们在父组件中编写 DOM 并在子组件渲染时把 DOM 添加到子组件的插槽中,使用起来非常方便。
在实现上,Vue 组件的插槽内容会被编译为插槽函数,插槽函数的返回值就是向槽位填充的内容。<slot>
标签则会被编译为插槽函数的调用,通过执行对应的插槽函数,得到外部向槽位填充的内容(即虚拟 DOM),最后将该内容渲染到槽位中。
参考:https://zhuanlan.zhihu.com/p/693009138
django的中间件有哪些?
1) SecurityMiddleware
django.middleware.security.SecurityMiddleware:
安全中间件负责处理与网站安全相关的任务
例如设置HTTP头部,防止跨站脚本攻击(XSS),点击劫持等。
它可以通过配置自定义安全策略来确保网站的安全性。
(2) SessionMiddleware
django.contrib.sessions.middleware.SessionMiddleware:
会话中间件负责处理用户会话的创建之间存储和检索用户数据。
它基于浏览器提供的Cookie或URL传递的会话ID进行会话跟踪,并将会话数据存储在后端数据库或缓存中,以实现用户状态的跨请求保持。
(3) CommonMiddleware
django.middleware.common.CommonMiddleware:
通用中间件提供了一些常见而关键的HTTP请求处理功能
例如,根据请求的HTTP头信息设置语言、时区等。
此外,它还处理静态文件的serving,包括收集静态文件,为其生成URL,并在开发模式下提供静态文件的serving。
(4) CsrfViewMiddleware
django.middleware.csrf.CsrfViewMiddleware:
CSRF(Cross-Site Request Forgery)中间件用于防止跨站请求伪造攻击。
它在每个POST请求中验证一个CSRF标记,确保请求是通过合法的表单提交得到的,从而保护用户免受恶意站点的攻击。
(5) AuthenticationMiddleware
django.contrib.auth.middleware.AuthenticationMiddleware:
认证中间件负责处理用户身份认证相关的任务
例如将认证信息关联到请求对象上,为每个请求提供一个user对象,以便在请求处理过程中轻松地获取和使用用户身份信息。
(6) MessageMiddleware
django.contrib.messages.middleware.MessageMiddleware:
消息中间件用于在请求处理过程中存储和传递临时的、一次性的用户消息。
它允许在HTTP重定向之间跨请求传递消息,例如成功或错误提示,以改善用户体验。
(7) XFrameOptionsMiddleware
django.middleware.clickjacking.XFrameOptionsMiddleware:
点击劫持中间件用于防止页面被嵌入到其他网站中,从而提供一定的点击劫持保护。
它通过设置X-Frame-Options HTTP头部来限制页面的显示方式,从而防止恶意网页通过iframe等方式嵌入当前网页。
参考链接:https://blog.csdn.net/qq_53842456/article/details/134584025
谈谈redis的使用场景
如上所述。