缺少 Apps 脚本网络挂钩和 Access-Control-Allow-Origin header
Apps Script webhooks and Access-Control-Allow-Origin header missing
我有一个 Google Apps 脚本项目充当网络挂钩。使用 htmx 之类的库调用端点时,预检检查失败,请求随后失败。直接用fetch
或XMLHttpRequest
调用时,没问题。
I have a sample endpoint 用简单的 doPost
进行测试:
const doPost = (request = {}) => {
const { postData: { contents, type } = {} } = request;
return ContentService.createTextOutput(contents);
};
此 Codepen 示例显示了使用 HTMX 的请求如何在 fetch
和 XHRHttpRequest
成功时失败。
我学到的一些东西:
- 预检中发送的
OPTIONS
header 导致 405 错误,完全中止请求。您可以通过 Postman(或类似工具)向 Web 应用程序 URL. 发送 OPTIONS
请求来模仿这一点
- 错误不包括
Access-Control-Allow-Origin
header,这是控制台中显示的失败原因。
- HTMX 发送 non-standard headers, which trigger preflight requests in modern browsers. However, you can strip all headers out, which should bypass the preflight, but doesn't. See this related discussion in the repo.
遇到这种情况,最好的调试方法是什么?我不太确定还有什么方法可以让它正常工作。
这是 HTMX 的问题,需要修改其源代码。问题的根源是HTMX在xhr.upload
that makes the browsers mark the request as "not simple"中添加了一些事件监听器,触发了CORS预检请求:
If the request is made using an XMLHttpRequest object, no event listeners are registered on the object returned by the XMLHttpRequest.upload property used in the request; that is, given an XMLHttpRequest instance xhr, no code has called xhr.upload.addEventListener() to add an event listener to monitor the upload
HTMX source code的具体部分:
forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) {
forEach([xhr, xhr.upload], function (target) {
target.addEventListener(eventName, function(event){
triggerEvent(elt, "htmx:xhr:" + eventName, {
lengthComputable:event.lengthComputable,
loaded:event.loaded,
total:event.total
});
})
});
});
遗憾的是,addEventListener
使用匿名函数,因此无法使用 removeEventListener
AFAIK 删除它们。
但是如果您愿意在您的应用程序中使用自定义 HTMX 脚本,直到作者解决此问题(例如添加防止在 xhr.upload
上创建事件侦听器的功能),只需删除 xhr.upload
来自第二行的列表:
forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) {
forEach([xhr], function (target) {
target.addEventListener(eventName, function(event){
triggerEvent(elt, "htmx:xhr:" + eventName, {
lengthComputable:event.lengthComputable,
loaded:event.loaded,
total:event.total
});
})
});
});
通过此修改,您原来通过 evt.detail.headers = []
删除 non-standard HTMX-specific headers 的建议将会奏效,因为现在此请求变得“简单”,因此不再需要 CORS预检由浏览器完成。
注意:修改可能会破坏HTMX文件上传,我没有测试。
我有一个 Google Apps 脚本项目充当网络挂钩。使用 htmx 之类的库调用端点时,预检检查失败,请求随后失败。直接用fetch
或XMLHttpRequest
调用时,没问题。
I have a sample endpoint 用简单的 doPost
进行测试:
const doPost = (request = {}) => {
const { postData: { contents, type } = {} } = request;
return ContentService.createTextOutput(contents);
};
此 Codepen 示例显示了使用 HTMX 的请求如何在 fetch
和 XHRHttpRequest
成功时失败。
我学到的一些东西:
- 预检中发送的
OPTIONS
header 导致 405 错误,完全中止请求。您可以通过 Postman(或类似工具)向 Web 应用程序 URL. 发送 - 错误不包括
Access-Control-Allow-Origin
header,这是控制台中显示的失败原因。 - HTMX 发送 non-standard headers, which trigger preflight requests in modern browsers. However, you can strip all headers out, which should bypass the preflight, but doesn't. See this related discussion in the repo.
OPTIONS
请求来模仿这一点
遇到这种情况,最好的调试方法是什么?我不太确定还有什么方法可以让它正常工作。
这是 HTMX 的问题,需要修改其源代码。问题的根源是HTMX在xhr.upload
that makes the browsers mark the request as "not simple"中添加了一些事件监听器,触发了CORS预检请求:
If the request is made using an XMLHttpRequest object, no event listeners are registered on the object returned by the XMLHttpRequest.upload property used in the request; that is, given an XMLHttpRequest instance xhr, no code has called xhr.upload.addEventListener() to add an event listener to monitor the upload
HTMX source code的具体部分:
forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) {
forEach([xhr, xhr.upload], function (target) {
target.addEventListener(eventName, function(event){
triggerEvent(elt, "htmx:xhr:" + eventName, {
lengthComputable:event.lengthComputable,
loaded:event.loaded,
total:event.total
});
})
});
});
遗憾的是,addEventListener
使用匿名函数,因此无法使用 removeEventListener
AFAIK 删除它们。
但是如果您愿意在您的应用程序中使用自定义 HTMX 脚本,直到作者解决此问题(例如添加防止在 xhr.upload
上创建事件侦听器的功能),只需删除 xhr.upload
来自第二行的列表:
forEach(['loadstart', 'loadend', 'progress', 'abort'], function(eventName) {
forEach([xhr], function (target) {
target.addEventListener(eventName, function(event){
triggerEvent(elt, "htmx:xhr:" + eventName, {
lengthComputable:event.lengthComputable,
loaded:event.loaded,
total:event.total
});
})
});
});
通过此修改,您原来通过 evt.detail.headers = []
删除 non-standard HTMX-specific headers 的建议将会奏效,因为现在此请求变得“简单”,因此不再需要 CORS预检由浏览器完成。
注意:修改可能会破坏HTMX文件上传,我没有测试。