【面试宝典】线上问题逆向分析1

问题一:前后端联动互相干扰(字段覆盖)

问题根因:数据所有权边界模糊,缺乏数据防护机制。

角色 具体改进措施
后端 1. 数据分层防御 : - 创建ContractSaveRequestDTO,仅包含前端可修改字段 - 自动管理字段(id、createTime、creator等)坚决不放入DTO - 使用@JsonIgnore防止敏感字段意外序列化到前端 2. 字段权限控制 : - Service层显式设置后端管理字段:entity.setCreateTime(now()) - 使用Bean Validation验证入参字段范围 3. 接口文档化:Swagger明确标注每个字段的读写权限
前端 1. 数据提交规范 : - 提交前使用lodash.omit过滤只读字段 - 创建专门的submitData对象,不与页面显示数据混用 2. 请求拦截器 :全局axios拦截器中添加字段过滤逻辑 3. 代码审查清单:将"不提交只读字段"加入团队Code Review清单
QA 1. 契约测试 : - 使用Pact验证接口字段权限定义 - 自动化检查后端不会返回敏感字段 2. 安全专项测试 : - 使用Burp Suite尝试修改只读字段,验证后端防护 - 设计"字段覆盖"专项测试用例 3. 自动化回归:将字段权限检查加入API自动化测试

技术实现示例

javascript 复制代码
// 前端 - 数据清洗
const submitData = {
  ...formData,
  // 显式排除后端管理字段
  id: undefined,
  createTime: undefined, 
  creator: undefined
}

// 后端 - 清晰的DTO设计
public class ContractSaveRequest {
    @NotBlank
    private String title;       // 前端可修改
    
    @NotBlank  
    private String content;     // 前端可修改
    
    // 不包含createTime、creator等后端字段
}

public class ContractService {
    public Contract saveContract(ContractSaveRequest request) {
        Contract entity = convertToEntity(request);
        // 后端确保设置管理字段
        entity.setCreateTime(LocalDateTime.now());
        entity.setCreator(getCurrentUser());
        return repository.save(entity);
    }
}

问题二:Word转PDF失败(特殊格式兼容性)

问题根因:对复杂格式文档兼容性不足,缺乏渐进式降级方案。

角色 具体改进措施
后端 1. 多引擎降级策略 : - 策略模式:Aspose → iText → LibreOffice 依次尝试 - 基于历史成功率智能选择最优引擎 2. 文档预处理 : - 检测文档复杂度,复杂文档直接使用最强引擎 - 移除异常格式、标准化字体 3. 异步化处理 : - 提交转换任务到RabbitMQ异步处理 - 提供任务状态查询接口 /api/tasks/{taskId}/status
前端 1. 用户体验优化 : - 上传时检测文件大小和类型,过大文件提前警告 - 转换中显示进度条和预计等待时间 2. 降级体验 : - 转换失败时提供"下载原Word文件"备选方案 - 复杂文档提示"转换时间较长,请耐心等待" 3. 状态轮询:定时查询转换状态,成功自动刷新
QA 1. 兼容性测试矩阵 : - 构建复杂格式测试库(表格、图表、公式、特殊字体) - 定期运行全引擎兼容性测试套件 2. 混沌工程测试 : - 模拟各转换引擎宕机、超时、内存溢出 - 验证降级策略和系统韧性 3. 性能基准测试:建立各引擎的性能基准,监控性能衰减

技术实现示例

java 复制代码
// 后端 - 多引擎降级策略
@Service
@Slf4j
public class DocumentConverter {
    private final List<ConverterStrategy> strategies;
    
    public ConversionResult convertToPdf(File wordFile) {
        // 预处理:检测文档复杂度
        DocumentComplexity complexity = analyzeComplexity(wordFile);
        
        for (ConverterStrategy strategy : getStrategyOrder(complexity)) {
            try {
                log.info("Trying converter: {}", strategy.getName());
                ConversionResult result = strategy.convert(wordFile);
                metrics.recordSuccess(strategy.getName());
                return result;
            } catch (UnsupportedFormatException e) {
                log.warn("{} unsupported format, trying next", strategy.getName());
                continue; // 格式不支持,继续尝试
            } catch (ConversionException e) {
                log.warn("{} conversion failed, trying next", strategy.getName());
                metrics.recordFailure(strategy.getName());
                // 其他异常,继续尝试
            }
        }
        // 全部失败时的业务降级
        return ConversionResult.fallback("转换失败,请下载Word原文件");
    }
}

问题三:接口幂等导致合同重复创建

问题根因:幂等性保障机制不完整,第三方调用链断裂。

角色 具体改进措施
后端 1. 统一幂等框架 : - 开发@Idempotent注解+AOP切面 - Redis原子操作(SETNX)实现防重校验 2. 第三方调用规范 : - 主动生成幂等键idempotentKey = "contract_"+bizId+"_"+MD5(参数) - 调用第三方时强制校验幂等键传递 3. 多级防重:数据库唯一索引 + Redis防重 + 业务逻辑校验
前端 1. 生成幂等键 : - 每次提交生成唯一Idempotency-Key(UUIDv4) - 放在HTTP Header中:Idempotency-Key: <uuid> 2. 交互防重 : - 提交后立即禁用按钮 + Loading状态 - 路由跳转时清理本地幂等键 3. 错误处理:接收到幂等错误时提示"请求已提交,请勿重复操作"
QA 1. 并发专项测试 : - JMeter模拟相同请求并发提交(相同幂等键) - 验证是否只成功一次且结果一致 2. 幂等键有效性测试 : - 测试页面刷新、浏览器回退等场景的幂等性 - 验证幂等键生成规则的全局唯一性 3. 第三方集成测试 : - Mock第三方服务验证幂等键传递正确性 - 测试第三方超时、重试场景下的系统行为

技术实现示例

java 复制代码
// 后端 - 幂等框架
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
    String key() default "";     // 幂等键表达式
    long expireTime() default 10 * 60; // 过期时间(秒)
}

@Aspect
@Component
@Slf4j
public class IdempotentAspect {
    
    @Around("@annotation(idempotent)")
    public Object checkIdempotent(ProceedingJoinPoint joinPoint, 
                                  Idempotent idempotent) throws Throwable {
        String key = generateKey(joinPoint, idempotent);
        
        // Redis原子操作防重
        Boolean firstRequest = redisTemplate.opsForValue()
            .setIfAbsent(key, "PROCESSING", idempotent.expireTime(), TimeUnit.SECONDS);
            
        if (Boolean.FALSE.equals(firstRequest)) {
            // 重复请求,返回缓存结果
            Object cachedResult = redisTemplate.opsForValue().get(key + "_RESULT");
            if (cachedResult != null) {
                log.info("Return cached result for idempotent key: {}", key);
                return cachedResult;
            }
            throw new IdempotentException("请求正在处理中,请勿重复提交");
        }
        
        try {
            Object result = joinPoint.proceed();
            // 缓存成功结果
            redisTemplate.opsForValue()
                .set(key + "_RESULT", result, idempotent.expireTime(), TimeUnit.SECONDS);
            return result;
        } catch (Exception e) {
            // 业务失败,删除幂等键允许重试
            redisTemplate.delete(key);
            throw e;
        }
    }
}

// 第三方调用 - 主动传递幂等键
@Service
public class ThirdPartyService {
    public void callExternalService(Contract contract) {
        // 主动生成并传递幂等键
        String idempotentKey = "contract_" + contract.getId() + "_" + 
                              DigestUtils.md5DigestAsHex(contract.toString().getBytes());
        
        ThirdPartyRequest request = ThirdPartyRequest.builder()
            .idempotentKey(idempotentKey)  // 关键:主动传递
            .data(contract.getData())
            .build();
            
        thirdPartyClient.invoke(request);
    }
}
相关推荐
han_1 小时前
前端高频面试题之CSS篇(一)
前端·css·面试
美团程序员1 小时前
一篇文章教你搞定:”xx 功能如何测试?“常见面试题型!
测试工具·面试·职场和发展·测试用例
墨染点香3 小时前
LeetCode 刷题【172. 阶乘后的零】
算法·leetcode·职场和发展
谷隐凡二4 小时前
Server-Client二层架构简单说明
面试
豆奶特浓66 小时前
Java面试模拟:当搞笑程序员谢飞机遇到电商秒杀与AIGC客服场景
java·spring boot·微服务·面试·aigc·高并发·电商
拉不动的猪7 小时前
Axios 请求取消机制详解
前端·javascript·面试
铭哥的编程日记7 小时前
《斩获字节跳动offer 最详细的面试真题与破解思路》第一期
面试·职场和发展
大侠课堂7 小时前
互联网大厂面试题100道-阿里百度篇-完整版
百度·阿里云·面试·面试题·阿里
Heo8 小时前
关于XSS和CSRF,面试官更喜欢这样的回答!
前端·javascript·面试