You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FeathersJS 5从Microsoft Graph API取数据存入MS SQL失败排查

问题根源与解决方案

核心问题分析

  1. 字段映射完全不匹配:conference-rooms.class.js的create方法中,错误使用了Graph API返回的原始字段(room.id/room.nickname/room.emailAddress),但roomFetcher返回的是已经格式化后的room_id/room_name/room_mail字段,导致插入时所有字段值为undefined,触发Schema验证静默失败。
  2. Graph API授权无效:roomFetcher.js中硬编码了TOKEN_IS_HERE,未使用传入的accessToken,可能导致获取不到会议室数据或返回空数组。
  3. FeathersJS服务配置缺失:默认create方法仅支持单个对象,批量创建需显式开启multi: true,否则会被服务层拦截。
  4. 错误捕获不完整:create方法内部的数据库插入错误未单独捕获,无法定位具体失败原因。

分步修复方案

1. 修正字段映射错误

修改conference-rooms.class.js的create方法,使用格式化后的字段名:

async create(rooms) {
  const ConferenceRoom = this.Model;
  // 兼容单个对象(手动提交)和数组(批量导入)两种场景
  const roomList = Array.isArray(rooms) ? rooms : [rooms];

  const createdRooms = [];
  for (const room of roomList) {
    const newRoom = await ConferenceRoom.query().insert({
      room_id: room.room_id,
      room_name: room.room_name,
      room_mail: room.room_mail
    });
    createdRooms.push(newRoom);
  }

  // 保持返回格式与输入一致
  return Array.isArray(rooms) ? createdRooms : createdRooms[0];
}

2. 修复Graph API授权头

在roomFetcher.js中正确使用传入的accessToken:

headers: {
  Authorization: `Bearer ${this.accessToken}`
}

3. 开启批量创建支持

修改conference-rooms.class.js的getOptions配置,允许批量操作:

export const getOptions = (app) => {
  return {
    paginate: app.get('paginate'),
    Model: app.get('mssqlClient'),
    name: 'conference_rooms',
    multi: true // 启用批量创建/更新/删除
  }
}

4. 增强数据验证与错误日志

在create方法中添加Schema验证,提前拦截无效数据:

import { conferenceRoomsDataValidator } from './conference-rooms.schema.js';

async create(rooms) {
  const ConferenceRoom = this.Model;
  const roomList = Array.isArray(rooms) ? rooms : [rooms];

  // 验证每条数据是否符合Schema要求
  for (const room of roomList) {
    const validationResult = conferenceRoomsDataValidator(room);
    if (!validationResult.valid) {
      throw new Error(`无效会议室数据: ${JSON.stringify(validationResult.errors)}`);
    }
  }

  const createdRooms = [];
  for (const room of roomList) {
    try {
      const newRoom = await ConferenceRoom.query().insert({
        room_id: room.room_id,
        room_name: room.room_name,
        room_mail: room.room_mail
      });
      createdRooms.push(newRoom);
    } catch (dbError) {
      console.error(`插入会议室 ${room.room_id} 失败:`, dbError);
      throw dbError; // 可根据需求改为跳过错误继续插入
    }
  }

  return Array.isArray(rooms) ? createdRooms : createdRooms[0];
}

额外优化建议

  • 批量插入提升性能:将循环插入改为Knex批量插入,减少数据库请求次数:
    const createdRooms = await ConferenceRoom.query().insert(roomList);
    
  • 处理Graph API空字段:为可能为空的字段添加默认值,避免验证失败:
    const formattedRooms = data.value.map((room) => ({
      room_id: room.id,
      room_name: room.nickname || room.displayName || '未命名会议室',
      room_mail: room.emailAddress || ''
    }))
    

内容的提问来源于stack exchange,提问作者Daniel Tršťanský

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 06:14:54