我在 blog.domain.com 上托管了一个博客;我想使用 Cloudflare 工作人员将其从子域切换到子目录。除了文件上传之外一切正常。当我上传文件时,浏览器会发送带有 formData 的 xhr post 请求。
Request URL:
https://www.domain.in/blog/ghost/api/admin/images/upload/
Request Method:
POST
Status Code:
422 Unprocessable Content
Referrer Policy:
strict-origin-when-cross-origin
内容类型由浏览器设置用于文件上传
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryglip7bP33nuVUYAE
Cloudflare 工作人员代码:
/**
* Welcome to Cloudflare Workers! This is your first worker.
*
* - Run `npm run dev` in your terminal to start a development server
* - Open a browser tab at http://localhost:8787/ to see your worker in action
* - Run `npm run deploy` to publish your worker
*
* Learn more at https://developers.cloudflare.com/workers/
*/
export interface Env {
// Example binding to KV. Learn more at https://developers.cloudflare.com/workers/runtime-apis/kv/
// MY_KV_NAMESPACE: KVNamespace;
//
// Example binding to Durable Object. Learn more at https://developers.cloudflare.com/workers/runtime-apis/durable-objects/
// MY_DURABLE_OBJECT: DurableObjectNamespace;
//
// Example binding to R2. Learn more at https://developers.cloudflare.com/workers/runtime-apis/r2/
// MY_BUCKET: R2Bucket;
//
// Example binding to a Service. Learn more at https://developers.cloudflare.com/workers/runtime-apis/service-bindings/
// MY_SERVICE: Fetcher;
//
// Example binding to a Queue. Learn more at https://developers.cloudflare.com/queues/javascript-apis/
// MY_QUEUE: Queue;
}
export default {
async fetch(request : Request){
async function handleRequest(request : Request) {
const url = new URL(request.url);
const originUrl = url.toString().replace("https://www.domain.in", "https://blog.domain.in");
const cookieHeader = request.headers.get("Cookie");
const headers = new Headers(request.headers);
if (cookieHeader) {
headers.append("Cookie", cookieHeader);
}
let originPage;
if (["POST", "PUT", "DELETE"].includes(request.method)) {
let contentType = request.headers.get("Content-Type") ;
if (contentType && contentType.includes("multipart/form-data")) {
let formData = await request.formData();
originPage = await fetch(originUrl, {
method: request.method,
headers,
body: formData,
});
} else {
originPage = await fetch(originUrl, {
method: request.method,
headers,
body: await request.text(),
});
}
} else {
originPage = await fetch(originUrl, {
method: request.method,
headers,
});
}
const newResponse = new Response(originPage.body, originPage);
return newResponse;
};
const response = await handleRequest(request);
return response ;
}
};
请求正在到达源服务器,但 multer 没有填充路径。所以文件上传被拒绝,说验证错误。 注意:当我从 blog.domain.in 上传时,上传工作正常(即没有 cloudflare 工作人员)
[90mValidationError: Please select an image.
at uploadValidation (/var/lib/ghost/versions/5.74.0/core/server/web/api/middleware/upload.js:149:25)
at Layer.handle [as handle_request] (/var/lib/ghost/versions/5.74.0/node_modules/express/lib/router/layer.js:95:5)
at next (/var/lib/ghost/versions/5.74.0/node_modules/express/lib/router/route.js:144:13)
at /var/lib/ghost/versions/5.74.0/core/server/web/api/middleware/upload.js:76:9
at Immediate._onImmediate (/var/lib/ghost/versions/5.74.0/node_modules/multer/lib/make-middleware.js:53:37)
at process.processImmediate (node:internal/timers:478:21)[39m
[39m
[2023-11-28 04:36:17] [31mERROR[39m The "path" argument must be of type string or an instance of Buffer or URL. Received undefined
[31m
[31mThe "path" argument must be of type string or an instance of Buffer or URL. Received undefined[39m
[1m[37mError Code: [39m[22m
[90mERR_INVALID_ARG_TYPE[39m
可能是什么问题?预先感谢
wrangler.toml :
name = "ghost"
main = "src/index.ts"
compatibility_date = "2023-11-21"
route = { pattern = "https://www.domain.in/blog*", zone_name = "domain.in" }
(发布我上面评论中的解决方案。)
麻烦从这里来:
let formData = await request.formData();
originPage = await fetch(originUrl, {
method: request.method,
headers,
body: formData,
});
此代码解析并重新编码表单数据。这意味着将选择一个新的边界字符串。但是,原始请求中的 Content-Type 标头将被转移到子请求,并且它包含旧的边界字符串,该字符串对于新编码无效。您可以通过删除 Content-Type 标头来解决此问题,在这种情况下,Workers Runtime 将根据新的 FormData 编码自动重新生成它:
let formData = await request.formData();
headers.delete("Content-Type");
originPage = await fetch(originUrl, {
method: request.method,
headers,
body: formData,
});