MarSeventh / CloudFlare-ImgBed

CloudFlare 图床,基于 CloudFlare Pages 的免费图片托管解决方案,支持 Telegram Bot 和 Cloudflare R2 等多种存储方式!
https://demo-cloudflare-imgbed.pages.dev/
Creative Commons Zero v1.0 Universal
1.09k stars 984 forks source link

求助:浏览器使用fetch上传失败,报cors错误 #76

Closed foxhank closed 1 month ago

foxhank commented 2 months ago

大佬好!我有一个生成图片的网页,想把生成的图片使用fetch上传api上传到图床,随后返回链接。图床和网站使用同一主域名下的不同二级域名。但是我生成 图片后上传时,报CORS错误:

Access to fetch at 'https://pic.foxhank.top/upload' from origin 'https://aidraw.foxhank.top' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.

源代码如下:

async function uploadToImageHost(blob) {
                const formData = new FormData();
                formData.append("file", blob, 'generated-image.png'); 

                const myHeaders = new Headers();
                myHeaders.append(      "contentType", 'multipart/form-data',
                    "User-Agent", "Apifox/1.0.0 (https://apifox.com)"); //构建请求头

                const requestOptions = {
                    method: 'POST',
                    headers: myHeaders,
                    body: formData,
                    redirect: 'follow'
                };

                try {
                    const response = await fetch('https://pic.foxhank.top/upload', requestOptions);

                    if (!response.ok) {
                        document.getElementById('aiImage').src = Image;
                        throw new Error(`上传失败:${response.status} ${response.statusText}`);

                    }

                    const result = await response.json();

                    return `https://pic.foxhank.top${result[0].src}`;
                } catch (error) {
                    console.error('Upload Error:', error);
                    throw error;
                }
            }

尝试修改upload.js,但我一改整个上传都会崩掉(悲)求大佬解答!

MarSeventh commented 2 months ago

二级域名不同也算跨域访问。 可以在upload.js里面的这个地方改下响应头,应该可以允许跨域访问(如果*还是被cors拦截的话,可以改成你需要上传的域名):

res = new Response(
                JSON.stringify([{ 'src': `/file/${fullId}` }]), 
                {
                    status: 200,
                    headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }
                }
            );
foxhank commented 1 month ago

非常感谢大佬!使用简单fetch绕过cors问题了,感谢!

MarSeventh commented 1 month ago

非常感谢大佬!使用简单fetch绕过cors问题了,感谢!

具体怎么解决的可以分享一下吗(^.^)

foxhank commented 1 month ago

非常感谢大佬!使用简单fetch绕过cors问题了,感谢!

具体怎么解决的可以分享一下吗(^.^)

没改图床部分😂问题出在我的程序部分 原来我手动设置了请求头,浏览器认为这是一个复杂请求,就给图床端发送了option预检请求,但是图床端无法处理此请求,造成后面的逻辑无法运行

            async function uploadToImageHost(blob) {
                const formData = new FormData();
                formData.append("file", blob, 'generated-image.png'); // 使用文件名

                const myHeaders = new Headers();
                myHeaders.append(      "contentType", 'multipart/form-data',
                    "User-Agent", "Apifox/1.0.0 (https://apifox.com)");

                const requestOptions = {
                    method: 'POST',
                    headers: myHeaders,
                    body: formData,
                    redirect: 'follow'
                };

                try {
                    const response = await fetch('https://pic.foxhank.top/upload', requestOptions);

后来我发现直接传递文件作为请求体,浏览器就不会进行cors验证,相当于绕过了这个问题

try {
                    const response = await fetch('https://pic.foxhank.top/upload', {
                        method: 'POST',
                        body: formData,
                    });

ps:我试过修改upload.js,试图让其能处理option请求,但是没有成功😂还是返回405 Method Not Allow

export async function onRequestPost(context) {
    const { request, env, params, waitUntil, next, data } = context;

    if (request.method === 'OPTIONS') {
        // 预检请求处理
        return new Response(null, {
            status: 200,
            headers: {
                'Access-Control-Allow-Origin': '*',
                'Access-Control-Allow-Methods': 'POST, OPTIONS',
            }
        });
    }

   // ......其余
}
MarSeventh commented 1 month ago

懂了,修改后端无法处理,是因为函数名是onrequestpost,只会处理post请求,改成onrequest,里面加上处理options请求的逻辑就好了(^~^)