2

Frontend is in react, server is in node.js express. Trying to upload a file to the server (set up on amazon - everything works fine locally) using XMLHttpRequest I get an error:

Access to XMLHttpRequest at 'https://xxx/api/video' from origin 'https://xxx/' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

I upload the file in chunks (10mb each) and there is no problem when the file is smaller (<40mb), but the problem occurs when the file is larger. This is incomprehensible as each chunk is always 10mb but somehow the server rejects those chunks which are part of a larger file. Following this lead, I removed the content-range header, which contained information about the total file size, but it didn't help.

For the cors service, I use:

app.use(cors({
    origin: true,
    credentials: true
}));

Code to upload the file:

 const saveFile = () => {
        if(videoName.length < 1){
            setVidNameErr(true);
        }

        if((uploadedFile || videoData) && (videoName.length > 0)){
            setUploadProgress(0);

            //options
            const chunkSize = 10000000; // size of one chunk: 10 MB
            let videoId = '';
            let chunkCounter = 0;
            const file = recordingMode ? videoData[0] : uploadedFile;
            const fileSize = recordingMode ? videoData[0].size : uploadedFile.size;

            const createChunk = (videoId: string, start: number) => {
                chunkCounter ++;
                const chunkEnd = Math.min(start + chunkSize , fileSize);
                const chunk = file.slice(start, chunkEnd);
                    
                const formData = new FormData();
                if(videoId?.length > 0){
                    formData.append('videoId', videoId);
                }
                formData.append('title', videoName);
                formData.append('file', chunk);
                
                uploadChunk(formData, start, chunkEnd);
            }

            const updateProgress = (e: any) => {
                if (e.lengthComputable) {  
                    const numberOfChunks = Math.ceil(fileSize/chunkSize);
                    const percentComplete = Math.round(e.loaded / e.total * 100);
                    setUploadProgress(
                        Math.round(
                            (chunkCounter - 1) / numberOfChunks * 100 + percentComplete / numberOfChunks
                        )
                    )
                }
            }

            const uploadChunk = (formData: any, start: number, chunkEnd: number) => {
                setIsVideoBeingSent(true);

                const req = new XMLHttpRequest();
                const contentRange = "bytes " + start + "-" + (chunkEnd - 1) + "/" + fileSize;
                req.upload.addEventListener("progress", updateProgress);    
                req.open("POST", `${process.env.URL}/api/video`, true);
                req.withCredentials = true;
                req.setRequestHeader('lang', router.locale as string)
                req.setRequestHeader("Content-Range", contentRange);
                //req.setRequestHeader("Content-Type", 'multipart/form-data; boundary=--');
                
                req.onload = () => {
                    const resp = JSON.parse(req.response)

                    resp.statusCode === 401 && logoutUser()
                    setRequestErr({
                        mess: resp.message, 
                        code: resp.statusCode
                    })

                    videoId = resp.videoId;
                    start += chunkSize; 
                    
                    if(start < fileSize){
                        createChunk(videoId, start);
                    } else{
                        chunkCounter = 0;
                        setIsVideoBeingSent(false);
                        setModalType('info')
                        if(resp.status === 200){
                            setModalInfoType('success')
                        } else{
                            setModalInfoType('fail')
                        }
                    }
                }
                req.send(formData);
            }

            createChunk(videoId, 0);
        }
    };

Based on: https://api.video/blog/tutorials/uploading-large-files-with-javascript

Uploading a file via form using this code: https://www.geeksforgeeks.org/file-uploading-in-node-js/

works, however when changing the file upload using XMLHttpRequest the error from cors reappears.

What could be causing this problem and how to fix it?

Cery
  • 51
  • 2
  • 4
  • We’re you able to resolve it? I’m having the exact issue. When I send large chunks, I get the same error as you. – tim_woods Jun 19 '22 at 22:00
  • @tim_woods No, unfortunately I was not able to solve this on my server. I circumvented this by choosing Amazon S3 - I upload files directly there. – Cery Jun 21 '22 at 17:16
  • I was able to solve my issue. I was calling app.use(cors) in the next line after express router. Cors needs to be called before the express router – tim_woods Jun 24 '22 at 02:31

2 Answers2

1

You need to allow your domain on your app. So add given code in your app.js.

app.use(function(req,res,next) {
    req.connection.setNoDelay(true)
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    res.header("Access-Control-Allow-Credentials", true);
        res.header("Access-Control-Allow-Origin", "https://xxx"); 

    res.header('Access-Control-Expose-Headers', 'agreementrequired');
  
    next()
})

you need to change only the domain name. https://xxx

Pushpendra Kumar
  • 1,721
  • 1
  • 15
  • 21
  • 1
    I use the cors module, which does exactly the same thing, so this is not a problem. The whole site works fine. As I wrote - uploading smaller files doesn't do any problems either. Of course I checked that code you posted and the problem is exactly the same. – Cery Jan 11 '22 at 12:00
  • We’re you able to resolve it? I’m having the exact issue. When I send large chunks, I get that error. – tim_woods Jun 19 '22 at 21:59
1

This is related: CORS error upload file ~4mb

The short answer is - for some reason nginx ingress rejects you via cors when your setting for client_max_body_size is insufficient to serve request. Increase this value to whatever you need and you should be good to go.

Zuum Dj
  • 86
  • 4