鹰角一面
印象非常深刻的一场面试,十分考验整体架构能力和实操能力。没有八股,全是场景。
场景题:
1.并发请求控制器
请实现一个函数 createRequestPool(limit)
,用于控制异步请求的并发数量。
要求:
- createRequestPool(limit) 返回一个函数 add(task),task 是一个返回 Promise 的函数。
- 最多只能有 limit 个任务同时执行,其余任务需要排队。
- 当一个任务完成后,应自动开始下一个任务。
- 所有任务最终都能执行完成。
示例:
function mockTask(id, delay) {
return () =>
new Promise((resolve) => {
setTimeout(() => {
console.log("done:", id);
resolve(id);
}, delay);
});
}
const pool = createRequestPool(2);
pool.add(mockTask(1, 300));
pool.add(mockTask(2, 200));
pool.add(mockTask(3, 100));
pool.add(mockTask(4, 400));
function createRequestPool(limit: number) {
// code here
const queue = [];
let runningCount = 0;
const add = (task) => {
queue.push(task);
runNext();
}
const runNext = () => {
// 当有任务在排队,并且有空闲的执行名额时
while (queue.length > 0 && runningCount < limit) {
const task = queue.shift();
if (task) {
runningCount++;
task().finally(() => {
runningCount--;
runNext;
})
}
}
}
}
2.数据表设计 我们计划推出一个网页活动,持续 30 天:
- 用户可以设定自己的昵称,要求不能与其他用户重复;
- 用户每天登录可以获得 1 积分,活动期间最多获得 10 次;
- 用户可以花费1积分进行1次抽奖,奖品为 A / B / C 三种;
- 需要提供接口查询:
- 用户积分
- 用户抽奖记录
- 某个奖品的前 100 个中奖用户
- 请完成mysql数据表结构的设计
create table `user` (
id: string,
nickname: string,
points: int,
login_count: int,
created_at,
updated_at,
);
create table `login_records` (
id: string,
user_id: string,
login_data: string,
created_at,
// 保证不重复
UNIQUE KEY `uk_user_data` (`user_id`, `login_data`)
)
create table `lottery_draws` (
id: string,
user_id: string,
prize_type: A | B | C,
created_at,
)
如何实现单点登录
单点登录 (Single Sign-On, SSO)
目标:让用户只需登录一次,就可以访问所有相互信任的应用系统(分布在不同子域名的项目)。
核心思想:将登录认证的逻辑抽离出来,交给一个独立的、所有应用都信任的中央认证服务 (Central Authentication Service, CAS)。
工作流程简述:
假设你有三个应用 app1.yourdomain.com
, app2.yourdomain.com
和一个认证中心 auth.yourdomain.com
。
- 首次访问:用户访问
app1.yourdomain.com
的受保护页面。 - 检查登录状态:
app1
发现用户未登录,将用户重定向到认证中心auth.yourdomain.com
,并带上自己的回调地址(redirect_uri=app1.yourdomain.com/callback)
。 - 用户登录:用户在
auth.yourdomain.com
页面上输入用户名和密码。 - 认证成功:
- 认证中心校验成功后,会做两件事:
a. 在auth.yourdomain.com
的域下设置一个用于跟踪登录会话的 Cookie(例如session_id
)。
b. 生成一个一次性的授权码 (code),然后将用户重定向回app1
的回调地址,并附上这个 code:app1.yourdomain.com/callback?code=xxxx
。
- 认证中心校验成功后,会做两件事:
- 获取令牌:
app1
的后端收到 code 后,会向认证中心发起一个后端请求,用这个 code 换取一个 Access Token。 - 登录完成:
app1
验证 Token 有效,并为用户在app1.yourdomain.com
域下创建自己的会话(或将 Token 存在前端),用户成功登录app1
。
如何实现单点登录:
- 访问其他应用:现在,用户打开一个新的标签页访问
app2.yourdomain.com
。 - 再次重定向:
app2
发现用户未登录,同样将用户重定向到auth.yourdomain.com
。 - 免密认证:此时,认证中心的服务器收到了来自
app2
的请求,它检查浏览器发来的 Cookie,发现了之前登录时设置的session_id
。它知道这个用户已经登录过了! - 直接跳转:认证中心跳过登录页面,直接生成一个新的 code,并把用户重定向回
app2
的回调地址。 - 后续流程同步骤 5 和 6,用户无需再次输入密码就自动登录了
app2
。