1. 为什么前端在浏览器上渲染,不通过前端直接访问后端会有跨域问题?
跨域问题产生的原因:
- 浏览器的同源策略限制。
- 同源策略:指协议、域名和端口号必须一致,否则会被浏览器视为不同源,禁止资源的访问。
- 如果前端通过 JavaScript 调用的后端接口和页面来源的 URL 不一致,就会触发跨域问题。
常见跨域解决方案:
- CORS(跨域资源共享):
- 后端设置
Access-Control-Allow-Origin
等响应头允许跨域访问。
- 后端设置
- JSONP:
- 通过
<script>
标签加载 JSON 格式的数据,只支持 GET 请求。
- 通过
- 代理转发:
- 在前端开发中,利用代理服务器(如 Nginx、Node.js 等)转发请求,使前端的请求看起来像是从同源服务器发出的。
2. 前端工程需要安装 Nginx 插件才能解决跨域问题吗?
不一定。
- 使用 Nginx 作为代理服务器是解决跨域问题的一种方法,但不是唯一方法。
- Nginx 的跨域解决方式:
- 配置反向代理,将后端接口转发给前端相同的域名下。
- 配置
add_header Access-Control-Allow-Origin *
以直接允许跨域。
3. 什么是 WITH [RECURSIVE]?
WITH [RECURSIVE]
是 SQL 中用于定义**公共表表达式(Common Table Expression,简称 CTE)**的语法结构,允许在查询中定义临时结果集。
逐词解析语法:
WITH [RECURSIVE]
cte_name [(col_name [, col_name] ...)] AS (subquery)
[, cte_name [(col_name [, col_name] ...)] AS (subquery)] ...
WITH
:声明一个或多个临时结果集(CTE)。[RECURSIVE]
:指定递归 CTE,用于递归查询,例如树形结构。cte_name
:CTE 的名称,相当于临时表名。[(col_name [, col_name] ...)]
:可选,为 CTE 的列命名。AS
:关键字,表示定义 CTE。(subquery)
:CTE 的内容,可以是任意 SQL 查询语句。
4. 为什么两种递归 SQL 写法结果不同?
以下为两种写法的比较:
写法 1(正确):
WITH RECURSIVE t1 AS (
SELECT *
FROM course_category p
WHERE id = '1'
UNION ALL
SELECT t.*
FROM course_category t
INNER JOIN t1 ON t1.id = t.parentid
)
SELECT *
FROM t1
ORDER BY t1.id, t1.orderby;
写法 2(报错):
WITH RECURSIVE t1 AS (
SELECT *
FROM course_category p
WHERE id = '1'
UNION ALL
SELECT *
FROM course_category t
INNER JOIN t1 ON t1.id = t.parentid
)
SELECT *
FROM t1
ORDER BY t1.id, t1.orderby;
原因分析:
报错信息 [21000][1222] The used SELECT statements have a different number of columns
表示:
UNION ALL
操作要求两部分的列数和顺序完全一致。- 写法 2 中的
SELECT *
可能因为列的顺序或数量不同,导致与SELECT * FROM course_category p
不匹配。
解决方法:
显式列出字段,确保两部分 SELECT 的列数和顺序一致。
5. Java Stream API 示例分析
代码:
Map<String, CourseCategoryTreeDto> mapTemp = courseCategoryTreeDtos.stream()
.filter(item -> !id.equals(item.getId()))
.collect(Collectors.toMap(
key -> key.getId(),
value -> value,
(key1, key2) -> key2
));
逐步解析:
courseCategoryTreeDtos.stream()
:
将courseCategoryTreeDtos
转换为流对象,便于链式操作。.filter(item -> !id.equals(item.getId()))
:
使用过滤条件,排除id
匹配的元素。.collect(Collectors.toMap(...))
:
将流中的数据收集为Map
,指定了key
和value
的生成规则:key -> key.getId()
:
每个元素的id
作为 Map 的键。value -> value
:
每个元素本身作为 Map 的值。(key1, key2) -> key2
:
解决键冲突时的处理方式,保留后一个值。
6. RPC(远程过程调用)
概念:
RPC(Remote Procedure Call)是一种允许调用远程服务器上的方法,就像调用本地方法一样的技术。
核心特点:
- 封装底层通信细节:
隐藏网络通信、序列化等复杂过程,让远程调用看起来像本地调用。 - 跨语言支持:
许多现代 RPC 框架支持多语言互操作。
工作流程:
Client App --> Client Stub --> Network --> Server Stub --> Server App
- 客户端调用本地代理(Client Stub):
- 序列化方法和参数,发送到服务器。
- 服务端接收请求(Server Stub):
- 反序列化请求,调用实际方法。
- 返回结果:
- 服务端序列化结果,客户端反序列化结果,交给应用程序。
常见 RPC 框架:
- gRPC:高性能框架,支持多语言。
- Thrift:跨语言通信,提供接口定义语言(IDL)。
- Dubbo:适用于 Java 微服务系统。