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

Keycloak创建用户成功返回201但JSON解析失败无法获取用户ID

问题现象

调用Keycloak接口 http://localhost:8080/auth/admin/realms/RealmName/users 时报错:invalid json response body reason: Unexpected end of JSON input。
在user.js的keycloak_add_user逻辑中,需要获取Keycloak中新创建用户的ID。当前调用管理员接口创建用户后,用户实际已成功创建(接口返回201 Created状态),但解析响应时出现上述JSON解析错误,无法获取用户ID,导致后续无法为用户分配角色。

现有实现代码

const payload = {
                email: req.payload.email,
                firstName: req.payload.first_name,
                lastName: req.payload.last_name,
                credentials: [
                    {
                        type: 'password',
                        temporary: false,
                        value: req.payload.password,
                    },
                ],
                enabled: true,
                emailVerified: true,
                createdTimestamp: Date.now(),
                requiredActions: ['UPDATE_PASSWORD'],
            };
          const token = req.headers.authorization;
        const keycloak_add_user = await fetch(
                     `http://${process.env.KEYCLOAK_HOST}:${process.env.KEYCLOAK_PORT}/auth/admin/realms/${process.env.REALM_NAME}/users`,
                        {
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/json',
                                Authorization: token,
                            },
                            body: JSON.stringify(payload),
                        }
                    );
               console.log('keycloak_add_user',keycloak_add_user)
            if (keycloak_add_user.status !== 201 || !keycloak_add_user) {
                return h
                    .response({ error: keycloak_add_user.statusText })
                    .code(keycloak_add_user.status);
            }
            const keycloak_user = await keycloak_add_user.json();
            console.log('keycloak_user', keycloak_user)

接口实际返回响应

Response {
  size: 0,
  timeout: 0,
  [Symbol(Body internals)]: {
    body: PassThrough {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: true,
      [Symbol(kCapture)]: false,
      [Symbol(kCallback)]: null
    },
    disturbed: false,
    error: null
  },
  [Symbol(Response internals)]: {
    url: 'http://13.213.9.103:8080/auth/admin/realms/Rubick/users',
    status: 201,
    statusText: 'Created',
    headers: Headers { [Symbol(map)]: [Object: null prototype] },
    counter: 0
  }
}

问题根因

  • Keycloak创建用户的POST接口返回201 Created状态时,响应体为空,从返回的Response对象也能看到size: 0,直接调用.json()方法解析空内容必然触发JSON解析错误。
  • 新创建用户的ID不会放在响应体中,而是存放在响应头的Location字段里,值格式为/auth/admin/realms/{realm名}/users/{用户ID},最后一段就是需要的用户ID。
  • 原代码的状态判断逻辑顺序错误:先取keycloak_add_user.status再判断keycloak_add_user是否存在,极端场景会触发空指针报错。

修正方案

  1. 调整响应判断顺序,优先校验响应对象是否存在,避免空指针
  2. 移除对空响应体的JSON解析逻辑,从Location响应头中提取用户ID
  3. 若需要完整用户信息,拿到ID后单独发GET请求获取即可

修正后的代码:

const payload = {
    email: req.payload.email,
    firstName: req.payload.first_name,
    lastName: req.payload.last_name,
    credentials: [
        {
            type: 'password',
            temporary: false,
            value: req.payload.password,
        },
    ],
    enabled: true,
    emailVerified: true,
    createdTimestamp: Date.now(),
    requiredActions: ['UPDATE_PASSWORD'],
};
const token = req.headers.authorization;
const keycloak_add_user = await fetch(
    `http://${process.env.KEYCLOAK_HOST}:${process.env.KEYCLOAK_PORT}/auth/admin/realms/${process.env.REALM_NAME}/users`,
    {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            Authorization: token,
        },
        body: JSON.stringify(payload),
    }
);
console.log('keycloak_add_user', keycloak_add_user)
// 先判断响应对象存在,再校验状态码
if (!keycloak_add_user || keycloak_add_user.status !== 201) {
    return h
        .response({ error: keycloak_add_user?.statusText || '请求Keycloak失败' })
        .code(keycloak_add_user?.status || 500);
}
// 从Location响应头提取用户ID
const location = keycloak_add_user.headers.get('Location');
const keycloak_user_id = location.split('/').pop();
console.log('新创建Keycloak用户ID:', keycloak_user_id);

// 后续可直接使用keycloak_user_id进行角色分配操作
// 若需要完整用户信息,可发起GET请求:GET /auth/admin/realms/{realm}/users/{keycloak_user_id}

补充说明:Keycloak所有创建类管理员接口(创建用户、角色、用户组、客户端等)返回201状态时,都遵循相同逻辑:响应体为空,新建资源的路径放在Location响应头中。

内容的提问来源于stack exchange,提问作者charu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 00:18:23