Azure Function 在 2022 年 4 月 26 日禁用了对 HTTP 请求对象的设置 "user" 字段
Azure Function disabled setting "user" field to HTTP request object on the 26th of April 2022
(!)问题无法在本地重现。
Azure 函数版本 ~4
节点版本 14.18.1
创建一个简单的 HTTP 触发的 Azure 函数并设置两个简单的属性,我们得到以下代码:
module.exports = async function (context, req) {
req.auth = {authField: 'some value'}
req.user = {userField: 'some value'}
context.log(`${JSON.stringify(req,null,2)}`);
context.res = {
body: 'responseMessage'
};
}
记录器打印以下对象:
{
"method": "POST",
"url": "xxx",
"originalUrl": "xxx",
"headers": {
/// ...
},
"query": {},
"params": {},
"body": { "name": "Azure" },
"rawBody": "{\"name\":\"Azure\"}",
"auth": { "authField": "some value" }
}
如您所见,仅设置了 auth
而未设置 user
。
在版本 4.2.0
.
中可以看到相同的失败行为
当我使用 Azure Function ~3 进行测试时,输出如下所示:
{
"method": "POST",
"url": "xxx",
"originalUrl": "xxx",
"headers": {
// ...
},
"query": {},
"params": {},
"body": { "name": "Azure" },
"rawBody": "{\"name\":\"Azure\"}",
"auth": { "authField": "some value" },
"user": { "userField": "some value" }
}
如您所见,字段已设置。
以下自定义 v4 4.1.0-17156
还设置了 user
字段。
字段 user
被我们通过 express-jwt (v6.1.0) which is using 使用,但没有为 requestProperty
提供任何值。
我还不能重现它,但在从 Typescript 项目转译出来时,我们得到以下运行时错误:
FailureException: Cannot set property user of [object Object] which has only a getterStack: TypeError: Cannot set property user of [object Object] which has only a getterat Object.run
问题从2022年4月26日开始。
问题:
- 这是什么原因?
- 是否可以快速回滚到正常运行的 Azure Functions 自定义版本?
我在 this PR 中找到了罪魁祸首,它是为 Azure Function runtime v4.2.0 添加的。
添加的用户字段只有 getter。
我们拿了代码并做了最小的例子:
class Request {
#cachedUser?: string | null;
constructor() {
}
get user(): string | null {
if (this.#cachedUser === undefined) {
this.#cachedUser = "some value";
}
return this.#cachedUser;
}
}
并得到以下转译版本:
var __classPrivateFieldGet =
(this && this.__classPrivateFieldGet) ||
function (receiver, state, kind, f) {
if (kind === 'a' && !f) throw new TypeError('Private accessor was defined without a getter')
if (typeof state === 'function' ? receiver !== state || !f : !state.has(receiver))
throw new TypeError('Cannot read private member from an object whose class did not declare it')
return kind === 'm' ? f : kind === 'a' ? f.call(receiver) : f ? f.value : state.get(receiver)
}
var __classPrivateFieldSet =
(this && this.__classPrivateFieldSet) ||
function (receiver, state, value, kind, f) {
if (kind === 'm') throw new TypeError('Private method is not writable')
if (kind === 'a' && !f) throw new TypeError('Private accessor was defined without a setter')
if (typeof state === 'function' ? receiver !== state || !f : !state.has(receiver))
throw new TypeError('Cannot write private member to an object whose class did not declare it')
return kind === 'a' ? f.call(receiver, value) : f ? (f.value = value) : state.set(receiver, value), value
}
var _Request_cachedUser
class Request {
constructor() {
_Request_cachedUser.set(this, void 0)
}
get user() {
if (__classPrivateFieldGet(this, _Request_cachedUser, 'f') === undefined) {
__classPrivateFieldSet(this, _Request_cachedUser, 'some value', 'f')
}
return __classPrivateFieldGet(this, _Request_cachedUser, 'f')
}
}
_Request_cachedUser = new WeakMap()
// this section is added for testing
const request = new Request()
request.user = 'new value'
console.log(JSON.stringify(request.user))
因此,它总是 returns 初始值,在我们的示例中是“某个值”,但在原始代码中只是 undefined
并且不允许设置它。
(!)问题无法在本地重现。
Azure 函数版本 ~4
节点版本 14.18.1
创建一个简单的 HTTP 触发的 Azure 函数并设置两个简单的属性,我们得到以下代码:
module.exports = async function (context, req) {
req.auth = {authField: 'some value'}
req.user = {userField: 'some value'}
context.log(`${JSON.stringify(req,null,2)}`);
context.res = {
body: 'responseMessage'
};
}
记录器打印以下对象:
{
"method": "POST",
"url": "xxx",
"originalUrl": "xxx",
"headers": {
/// ...
},
"query": {},
"params": {},
"body": { "name": "Azure" },
"rawBody": "{\"name\":\"Azure\"}",
"auth": { "authField": "some value" }
}
如您所见,仅设置了 auth
而未设置 user
。
在版本 4.2.0
.
当我使用 Azure Function ~3 进行测试时,输出如下所示:
{
"method": "POST",
"url": "xxx",
"originalUrl": "xxx",
"headers": {
// ...
},
"query": {},
"params": {},
"body": { "name": "Azure" },
"rawBody": "{\"name\":\"Azure\"}",
"auth": { "authField": "some value" },
"user": { "userField": "some value" }
}
如您所见,字段已设置。
以下自定义 v4 4.1.0-17156
还设置了 user
字段。
字段 user
被我们通过 express-jwt (v6.1.0) which is using 使用,但没有为 requestProperty
提供任何值。
我还不能重现它,但在从 Typescript 项目转译出来时,我们得到以下运行时错误:
FailureException: Cannot set property user of [object Object] which has only a getterStack: TypeError: Cannot set property user of [object Object] which has only a getterat Object.run
问题从2022年4月26日开始。
问题:
- 这是什么原因?
- 是否可以快速回滚到正常运行的 Azure Functions 自定义版本?
我在 this PR 中找到了罪魁祸首,它是为 Azure Function runtime v4.2.0 添加的。
添加的用户字段只有 getter。
我们拿了代码并做了最小的例子:
class Request {
#cachedUser?: string | null;
constructor() {
}
get user(): string | null {
if (this.#cachedUser === undefined) {
this.#cachedUser = "some value";
}
return this.#cachedUser;
}
}
并得到以下转译版本:
var __classPrivateFieldGet =
(this && this.__classPrivateFieldGet) ||
function (receiver, state, kind, f) {
if (kind === 'a' && !f) throw new TypeError('Private accessor was defined without a getter')
if (typeof state === 'function' ? receiver !== state || !f : !state.has(receiver))
throw new TypeError('Cannot read private member from an object whose class did not declare it')
return kind === 'm' ? f : kind === 'a' ? f.call(receiver) : f ? f.value : state.get(receiver)
}
var __classPrivateFieldSet =
(this && this.__classPrivateFieldSet) ||
function (receiver, state, value, kind, f) {
if (kind === 'm') throw new TypeError('Private method is not writable')
if (kind === 'a' && !f) throw new TypeError('Private accessor was defined without a setter')
if (typeof state === 'function' ? receiver !== state || !f : !state.has(receiver))
throw new TypeError('Cannot write private member to an object whose class did not declare it')
return kind === 'a' ? f.call(receiver, value) : f ? (f.value = value) : state.set(receiver, value), value
}
var _Request_cachedUser
class Request {
constructor() {
_Request_cachedUser.set(this, void 0)
}
get user() {
if (__classPrivateFieldGet(this, _Request_cachedUser, 'f') === undefined) {
__classPrivateFieldSet(this, _Request_cachedUser, 'some value', 'f')
}
return __classPrivateFieldGet(this, _Request_cachedUser, 'f')
}
}
_Request_cachedUser = new WeakMap()
// this section is added for testing
const request = new Request()
request.user = 'new value'
console.log(JSON.stringify(request.user))
因此,它总是 returns 初始值,在我们的示例中是“某个值”,但在原始代码中只是 undefined
并且不允许设置它。