node(koa)和python(fastapi)面试

node部分

1.node的koa和express的中间件模型对比?

Express:线性中间件(瀑布模型),而koa是洋葱模型

express(瀑布模型):

  • 普通中间件:(req,res,next)=>{}
  • 错误中间件:四个参数 (err, req, res, next)=>{}
  • 调用 next() 才进入下一个中间件;next 之后代码不会等后面中间件执行完 ,直接继续执行当前中间件剩下代码
    简单理解:顺序往下走,走完路由再一层层返回,不是洋葱。

koa(洋葱模型):

  • ctx:上下文,封装了 request 和 response,替代 express 的 req、res
  • await next() 是洋葱的关键;await 会暂停当前中间件,去执行下游,下游全部跑完,再回来执行 await 后面代码
bash 复制代码
// Koa中间件格式
async (ctx, next) => {
  console.log('前置')
  await next() // 等待下游所有中间件全部执行完毕,才回来执行下面代码
  console.log('后置')
}

比如app.use(async (ctx, next) => {
  console.log('First middleware (request phase)');
  await next();
  console.log('First middleware (response phase)');
});

app.use(async (ctx, next) => {
  console.log('Second middleware (request phase)');
  await next();
  console.log('Second middleware (response phase)');
});

app.use(async (ctx) => {
  console.log('Third middleware (final response)');
  ctx.body = 'Hello from Koa!';
});
 打印出来是:
 First middleware (request phase)
Second middleware (request phase)
Third middleware (final response)
Second middleware (response phase)
First middleware (response phase)

在上面的例子中,await next() 被调用后,程序会继续执行下一个中间件,并在后续中间件执行完成后返回。

一句话区分:

Express next () 是调用下一个中间件,不等待返回 ;

Koa await next() 等待下游全部执行完成,再回来执行后置逻辑

面试坑:Koa 中间件执行顺序口诀:先进后出,像剥洋葱

2. ctx 对象是什么?

ctx = context,请求上下文,每一次请求都会新建一个 ctx

  • ctx.request:封装原生 req
  • ctx.response:封装原生 res
  • 简写:ctx.url、ctx.method、ctx.body(最常用,设置响应体)、ctx.status状态码
  • ctx.query get 参数;ctx.params 需要 koa-router 支持

3. Koa 为什么不内置路由、静态资源?

Koa 设计理念:内核极简,只提供中间件洋葱模型,其他能力交给第三方生态:

  • 路由:koa-router
  • 静态资源:koa-static
  • body 解析:koa-bodyparser

4. Koa 的错误处理(高频)

1.全局错误中间件:放在所有中间件最前面(洋葱模型顺序!)

bash 复制代码
app.use(async (ctx, next) => {
  try {
    await next()
  } catch (err) {
    ctx.status = err.status || 500
    ctx.body = { code: 500, msg: err.message }
  }
})

2.主动抛出:ctx.throw(401, '未授权'),自动抛出错误对象

5. koa-bodyparser 作用

解析 post 请求 body,支持 json、表单;不能解析 multipart/form-data 上传文件 ,文件上传要用 koa-multer

python部分

一、FastAPI 基础概念

1. FastAPI 是什么?核心优势

  • 基于 Starlette(web 底层)+ Pydantic(数据校验)的现代 Python Web 框架;
  • 主打:自动 OpenAPI 文档、类型提示、自动数据校验、异步支持、高性能;
  • 对比 Flask/Django:
    • Flask:轻量,无内置校验,文档要手写,异步支持弱;
    • Django:大而全,重型 ORM,适合传统后台;
    • FastAPI:原生类型注解,自动校验 + 接口文档,同步 /async 混用,性能接近 Node/Go。

追问:Starlette 作用?

Starlette 是 ASGI web 框架,负责网络层:请求接收、路由、中间件、响应、websocket;FastAPI 在它之上封装,增加 Pydantic、依赖注入、openapi 生成。

2. ASGI 和 WSGI 的区别(必问)

  • WSGI:同步网关,只能处理同步代码,Django/Flask;一个请求占一个 worker;
  • ASGI:异步网关,支持 async/await,支持长连接(websocket、SSE);可以同时处理多个 IO 密集请求;
  • FastAPI 运行服务器:uvicorn、hypercorn;uvicorn 是 ASGI 服务器。

坑点:路由函数写普通 def,FastAPI 也能跑,uvicorn 会在线程池执行;只有 async def 才是原生异步。

Pydantic(FastAPI 灵魂,面试最高频)

1. Pydantic BaseModel 作用

  • 数据模型定义、请求入参校验、类型转换、序列化;
  • FastAPI 自动把请求 json → BaseModel 实例;返回模型自动转 json;
  • 校验失败自动返回 422,附带详细错误信息。

2. Pydantic v1 vs v2(非常高频!现在项目大多迁移 v2)

  • v1:底层 Python 实现;
  • v2:底层 Rust 重写,速度提升几十倍;API 有少量 breaking change;
  • 改动点:
    • @validator → @field_validator / @model_validator
    • orm_mode = True → model_config = ConfigDict(from_attributes=True)
    • .dict() → .model_dump();.json() → .model_dump_json()

面试必背:from_attributes=True 用来支持从 ORM 对象(sqlalchemy)直接转 Pydantic 模型。

3. 字段校验:常用约束

Field(gt=0, max_length=100, description="xxx")

  • 自定义校验:@field_validator 单字段校验;@model_validator(mode="before"/"after") 多字段联合校验。

4. 模型嵌套、可选字段、默认值、Optional / | None

复制代码
from typing import Optional
name: Optional[str] = None  # python3.9+ 等价 str | None

面试坑:name: str = None 会报错!类型声明 str 不能是 None,必须显式标记可空。

5. 序列化 exclude、include

model_dump(exclude={"password"}) 返回时剔除敏感字段,接口返回脱敏常用。

三、请求、参数类型(高频)

FastAPI 自动区分 4 种参数:

  1. 路径参数 Path :/items/{item_id},item_id
  2. 查询参数 Query :/items?limit=10,函数普通参数,不在路径里
  3. 请求体 Body :BaseModel,POST/PUT json;GET 不能带 body(http 规范)
  4. 表单参数 Form :Form(),multipart/form-data,上传文件、表单提交

区分口诀:

在路径 {} 里 → Path;

不在路径,且是基础类型 (int/str) → Query;

是 Pydantic 模型 → Body;

File/Form → 表单。

特殊参数

  • Path(..., ge=1):路径参数校验
  • Query(default=None, alias="page-size"):查询参数别名,前端用横杠,后端变量下划线
  • File() 上传文件,UploadFile 对象:.filename、.read()、.size

四、依赖注入 Depends(FastAPI 最有特色的考点,必问)

1. Depends 是什么?

依赖注入系统,把公共逻辑抽成依赖函数,路由函数声明依赖,框架自动执行并注入返回值。

典型场景:

  • 获取当前登录用户

  • 获取数据库 session

  • 权限校验

  • 请求日志、限流

    from fastapi import Depends

    def get_db():
    db = SessionLocal()
    try:
    yield db
    finally:
    db.close()

    @app.get("/")
    def hello(db = Depends(get_db)):
    ...

重点:yield 依赖(上下文依赖)

yield 之前:请求前执行;yield 返回值注入路由;yield 之后:请求结束后执行(关闭连接、释放资源)。

支持 async yield,同步 yield。

2. 依赖的作用域(面试高频)

  • 默认:每个请求一次。每个请求进来,新建依赖实例,请求结束销毁。
  • 没有全局单例(除非你自己用全局变量,不推荐,多线程 / 异步不安全)
  • 依赖可以嵌套:Depends 里面还可以 Depends。

3. 依赖里面抛异常

在依赖函数里直接 raise HTTPException(401),路由不会执行,直接返回错误,适合鉴权。

五、async /await 异步(重点,结合你的 Agent 项目)

1. 同步函数 def vs async def 路由函数

复制代码
@app.get("/sync")
def sync_func():
    # 同步代码,uvicorn放到线程池运行
    pass

@app.get("/async")
async def async_func():
    # ASGI原生异步,不要在这里写time.sleep()!要用await asyncio.sleep()
    pass

经典面试题:async 路由里面调用 time.sleep (10) 会发生什么?

✅ 答案:会阻塞整个事件循环!所有其他请求卡住。

异步代码中不能调用阻塞 IO(time.sleep、同步数据库、requests),要用异步库:httpx.AsyncClient、asyncpg。

同步 def 路由会丢到线程池,不会阻塞主事件循环,但线程池有上限。

2. 什么时候用 async?

IO 密集场景:数据库查询、http 调用(调用 LLM、RAG 向量库)、redis。

CPU 密集:不适合 async,放到任务队列(celery)。

3. 事件循环

ASGI 服务器启动一个主事件循环,async 代码都跑在这个循环里。

六、响应、状态码、响应模型

  1. response_model=UserRes:过滤输出字段,自动序列化,屏蔽敏感字段。

注意:response_model 是对返回结果做校验 + 序列化,不是入参。

  1. status_code=201:默认 200,创建资源用 201
  2. RedirectResponse、FileResponse、StreamingResponse

StreamingResponse(SSE 流式输出,你的 RAG/Agent 项目核心!大概率会问)

用于大模型流式打字效果,逐块返回文本,不会一次性加载全部内容。

要点:

  • 传入生成器函数(普通生成器 /async 生成器)
  • MediaType text/event-stream
  • 适合 RAG 对话,SSE 长连接;
  • 注意:如果用同步生成器,会占用线程池;优先 async 生成器。

七、异常处理(高频)

  1. HTTPException(status_code, detail="msg"):基础抛出,返回 http 错误。

  2. 全局异常处理器 @app.exception_handler(自定义异常类)

    from fastapi import Request
    @app.exception_handler(ValueError)
    async def value_error_handler(request: Request, exc: ValueError):
    return JSONResponse(status_code=400, content={"msg": str(exc)})

  3. 422 错误:Pydantic 校验失败,FastAPI 内置处理器。

  4. RequestValidationError:请求参数校验异常。

面试题:HTTPException 和 自定义异常区别?

HTTPException 是 FastAPI 内置,简单场景;自定义异常 + 全局 handler 统一返回业务错误码结构(code、msg、data),项目常用。

八、中间件 Middleware

FastAPI 中间件本质是 Starlette 中间件。两种写法:

  1. @app.middleware("http") 装饰器写法(async)

    @app.middleware("http")
    async def log_middleware(request: Request, call_next):
    # 请求前
    response = await call_next(request)
    # 请求后
    return response

  2. 继承 BaseHTTPMiddleware 类写法。

用途:全局日志、耗时统计、跨域 CORS、请求 ID 注入。

CORS:from fastapi.middleware.cors import CORSMiddleware,允许跨域前端访问。
注意:中间件在依赖注入之前执行;中间件捕获异常需要自己处理。

九、安全模块 OAuth2、JWT(后端必问)

复制代码
from fastapi.security import OAuth2PasswordBearer
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="login")
  1. OAuth2PasswordBearer:声明从 header Authorization: Bearer {token} 取 token。
  2. JWT 流程:登录成功,服务端生成 jwt 返回;后续请求携带 token;依赖里解析 token 拿到用户信息。
  3. JWT 组成:header.payload.signature;payload 不能存敏感信息(可解码)。
  4. 密码不要明文存储:passlib + bcrypt 哈希。

十、数据库相关(你项目里 PostgreSQL)

面试官喜欢问:同步 session vs async session

  1. SQLAlchemy v1/v2:同步 Session /async AsyncSession
  2. async 模式下:engine = create_async_engine (),session = AsyncSession
  3. 依赖 yield 方式管理 session:每次请求创建 session,请求结束自动 close。

坑:async session 里不能用同步 ORM 操作,必须 await。

十一、部署、性能、坑点

  1. uvicorn 启动命令:uvicorn main:app --workers 4 --host 0.0.0.0 --port 8000

workers:多进程;多进程下,全局变量不共享,每个进程独立一份 ;异步单进程单事件循环,多进程利用多核。

生产一般:uvicorn + nginx 反向代理。

  1. 性能调优:
  • Pydantic v2 升级;
  • 数据库连接池;
  • 慢 IO 使用异步客户端;
  • 避免阻塞代码;
  • 缓存 redis;
  • 大响应用 StreamingResponse。
  1. 常见坑
  • async 路由中调用同步阻塞库(requests/time.sleep)阻塞事件循环;
  • 忘记关闭数据库连接,连接池耗尽;
  • GET 请求传 body,http 规范不推荐,部分网关会丢弃 body;
  • 依赖中全局变量做状态,多进程 / 并发下数据错乱;
  • 忘记 CORS 导致前端跨域报错;
  • Pydantic v1 升级 v2 语法踩坑。
相关推荐
曲径海盗2 小时前
【Python 学习第 32 天】字符串基础
python·学习笔记·编程入门
田里的水稻2 小时前
PyTorch_torchvision---数据集下载\TensorBoard可视化
人工智能·pytorch·python·深度学习·机器学习
十年Java程序媛2 小时前
Java 多线程基础与锁机制|进程线程、synchronized、volatile、Lock 面试全梳理
java·spring boot·面试
程序员正茂2 小时前
Win11使用自定义训练集训练ncnn模型
python·yolo·图像识别·移动端·ncnn
zwd20052 小时前
Manim 画布尺寸与像素换算详解:frame_width、frame_height、pixel_width 和画质参数(0.21.0 实测)
python·分辨率·manim·数学动画·frame_width·manim教程
ShineWinsu2 小时前
对于CSS:弹性布局(Flexbox)的解析
前端·css·面试·浏览器·web·网页·弹性布局
最强小杰3 小时前
Claude Opus 4.8 调用报 529 怎么办?并发限制触发过载——退避策略与降级方案完整指南
运维·网络·python·ai
databook3 小时前
MinMax vs Standard vs Robust:三种特征缩放怎么选
python·机器学习·数据分析
在世修行3 小时前
智学文枢:实体模型层
python·orm·sqlalchemy