失败 - 使用 chrome 的 react dropzone 时下载错误

Failed- Download Error while using react dropzone with chrome

我的应用程序遇到了一个奇怪的问题。我想要实现的期望行为是在浏览器中提交一个表单(我正在使用 react-hook-form),在提交的表单中将有一些数据并且可以选择添加文件,在将表单提交到服务器之后我收到包含 PDF 文件的回复。到现在为止一切都很好,我有多种形式可以完美地工作(在这些形式中我仍然没有添加添加文件的选项)。但是,我尝试将 react-dropzone 添加到我的应用程序以进行文件上传。 现在可能有几种不同的情况:

  1. 未添加任何文件 - 我收到了很好的回复,里面有 PDF 文件。
  2. 通过单击上传组件并使用文件选择器选择文件来添加文件 - 我收到了很好的响应,其中包含 PDF 文件。
  3. 拖放文件 - 我收到 失败 - 下载错误,收到此错误后我下载了大约 100 个空的临时文件。

关于错误的几点说明:

  1. 似乎请求到达服务器时包含所有数据,服务器完成创建 PDF 文件并将其保存在 PC 上的工作,服务器 returns 状态码 200,所以看来问题不在服务器上。
  2. 好像问题只出现在Chrome(我使用的是最新版本95.0.4638.69),我尝试在edge上做同样的事情,它有效。
  3. 这个错误似乎使我电脑上的某些进程表现异常或卡住。由于出现此错误后,尝试在我的应用程序中下载其他文件会导致同样的问题,修复它的唯一方法是重新启动计算机(仅仅重新加载反应应用程序是不够的)。此外,在 chrome 中出现此错误后,我开始紧张起来。
  4. 起初我以为问题是我尝试发送文件,所以我从请求中删除了文件,但问题仍然存在。
  5. 控制台没有错误。

这是我的 FilesUploadStep,我在其中使用了 dropzone,因为它只是一个步骤,所以我有一个父组件,我将在稍后显示(我从此处的代码中删除了样式,以使其更短,如果有是否需要添加它们,请告诉我)

const FilesUploadStep = ({ files, handleSetFiles, stepNumber, handleRemoveFile, onSubmit }) => {
const classes = useStyles();

const { control, handleSubmit, formState: { errors } } = useForm({});

const onDropAccepted = useCallback((files) => {
    handleSetFiles(files)
}, [])

const { getRootProps, getInputProps, isDragActive, isDragAccept, isDragReject } = useDropzone({
    accept: 'image/jpeg, image/png, application/vnd.openxmlformats-officedocument.wordprocessingml.document, application/pdf',
    multiple: true,
    onDropAccepted
});

const style = useMemo(() => ({
    ...baseStyle,
    ...(isDragActive ? activeStyle : {}),
    ...(isDragAccept ? acceptStyle : {}),
    ...(isDragReject ? rejectStyle : {})
}), [
    isDragActive,
    isDragReject,
    isDragAccept
]);


return (
    <form id={`form-step-${stepNumber}`} onSubmit={handleSubmit(onSubmit)}>

        <div className={classes.formStepContainer}>
            <div className="container">
                <div {...getRootProps({ style })}>
                    <input {...getInputProps()} />
                    <BackupIcon fontSize="large" />
                    {!isDragActive && <p>"Drag here"</p>}
                    {isDragAccept && <p>"Accept"</p>}
                    {isDragReject && <p>"Reject"</p>}
                </div>
                <div>
                    {files.length > 0 &&
                        <Typography variant="h6" className={classes.title}>
                            {t('form114.filesUpload.subtitle')}
                        </Typography>}
                    <div className={classes.demo}>
                        <List >
                            {files.map((file) =>
                                <ListItem key={`${file.path}`} >
                                    <ListItemAvatar>
                                        <Avatar>
                                            {file.type === "application/vnd.openxmlformats-officedocument.wordprocessingml.document" && <DescriptionIcon />}
                                            {file.type === "application/pdf" && <DescriptionIcon />}
                                            {file.type.startsWith('image') && <ImageIcon />}
                                        </Avatar>
                                    </ListItemAvatar>
                                    <ListItemText
                                        primary={file.name}
                                    />
                                    <ListItemSecondaryAction>
                                        <IconButton edge="end" aria-label="delete" onClick={() => handleRemoveFile(file)}>
                                            <DeleteIcon />
                                        </IconButton>
                                    </ListItemSecondaryAction>
                                </ListItem>
                            )}
                        </List>
                    </div>
                </div>
            </div>
        </div >
    </form>
)}

这是我的带有提交方法的父组件(因为它是相当大的组件,我只尝试包含相关代码):

const myForm = (props) => {
const classes = useStyles();
const [activeStep, setActiveStep] = useState(0);
const [formValues, setFormValues] = useState(defaultValues);
const [files, setFiles] = useState([])


const handleSetFiles = (files) => {
    console.log("enter", files)
    setFiles(prev => [...prev, ...files])
}

const handleRemoveFile = (file) => {
    setFiles(prev => prev.filter(f => f.path !== file.path))
}

const onSubmit = (data) => {
    console.log("data", data)
    console.log("formValues" + JSON.stringify(formValues))
    if (activeStep === 4) {
        const finalData = {
            ...formValues.step1, ...formValues.step2, ...formValues.step3, paying_company: formValues.paying_company.id,
            known_relationship: convertStringToBoolean(formValues.step3.known_relationship),
            previous_payments_in_tax_year: convertStringToBoolean(formValues.step3.previous_payments_in_tax_year),
            payment_date: convertDateToString(formValues.step3.payment_date),
            previous_payment_date: convertDateToString(formValues.step3.previous_payment_date),
        }

        axios
            .post(process.env.REACT_APP_DJANGO_URL + "/form114/", finalData, {
                contentType: "multipart/form-data",
                responseType: "blob"
                               }
            )
            .then(response => {
                const url = window.URL.createObjectURL(new Blob([response.data]));
                const link = document.createElement('a');
                link.href = url;
                link.setAttribute('download', `Form 114 - ${formValues.paying_company.id}.pdf`); //or any other extension
                document.body.appendChild(link);
                link.click();
             })
            .catch((error) => console.log(error));

    }

    handleNext();
}

const handleNext = () => {
    setActiveStep((prevActiveStep) => prevActiveStep + 1);
};

function getStepFormPart(step) {
    switch (step) {
        case 4:
            return (
                <FilesUploadStep stepNumber={4} onSubmit={onSubmit} files={files} handleSetFiles={handleSetFiles} handleRemoveFile={handleRemoveFile} />
            );
        default:
            return;
    }
}

return (
    <div className={classes.root}>
        <h2 className="title">Form</h2>
        <Divider style={{
            height: "2px",
            backgroundColor: "#FFD400",
            marginTop: "5px"
        }} />
        <BackToOptionsButton />
        <div className={classes.stepperContainer}>

            <Stepper className={classes.stepper} activeStep={activeStep} orientation="vertical">
                {steps.map((label) => (
                    <Step key={label}>
                        <StepLabel classes={{ label: classes.step_label_root }}>
                            {label}
                        </StepLabel>
                        <StepContent>
                            <div className={classes.actionsContainer}>
                                <div>
                                    {activeStep !== 0 &&
                                        <Button
                                            onClick={handleBack}
                                            className={clsx(classes.button, classes.buttonOutlined)}
                                            variant="outlined"
                                        >
                                            {t('buttons.back')}
                                        </Button>
                                    }

                                    <Button
                                        variant="contained"
                                        color="primary"
                                        className={classes.button}
                                        type="submit"
                                        form={`form-step-${activeStep}`}
                                    >
                                        {activeStep === steps.length - 1 ? t('buttons.finish') : t('buttons.next')}
                                    </Button>
                                </div>
                            </div>
                        </StepContent>
                    </Step>
                ))}
            </Stepper>
            <div className={classes.formContainer}>
                {getStepFormPart(activeStep)}
            </div>
        </div>
        {
            activeStep === steps.length && (
                <Paper square elevation={0} className={classes.resetContainer}>
                    <Typography>All steps completed - you&apos;re finished</Typography>
                </Paper>
            )
        }
    </div >
)

}

The error I am getting

Some of the empty temp files I am getting

这个问题是我换了电脑才解决的。似乎是操作系统中的某些东西,或者可能是某些进程没有正常工作。