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是否存在,极端场景会触发空指针报错。
修正方案
- 调整响应判断顺序,优先校验响应对象是否存在,避免空指针
- 移除对空响应体的JSON解析逻辑,从
Location响应头中提取用户ID - 若需要完整用户信息,拿到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
相关产品推荐
相关产品推荐

