Support async upload parameters on XHR upload
lmyslinski opened this issue · comments
Initial checklist
- I understand this is a feature request and questions should be posted in the Community Forum
- I searched issues and couldn’t find anything (or linked relevant results below)
Problem
Currently, we can only pass in HTTP headers for XHR upload when creating an Uppy instance. This is a problem when the auth token is short-lived - in my case, the token is only valid for 60 seconds, however our clients often can keep the tab open for way longer than that. Currently I have a very ugly solution with periodically running an effect hook for recreating the Uppy instance:
const { getToken } = useAuth(); // async function for getting a new auth token value
const [token, setToken] = useState<string>(authToken);
const updateToken = async () => {
const res = await getToken();
if (res != null && res != token) {
setToken(res);
}
};
useEffect(() => {
const timer = setInterval(updateToken, 30000);
return () => clearInterval(timer);
}, []);
useEffect(() => {
const newUppy = getUppy(token);
setUppy(newUppy);
}, [token]);
const getUppy = (newToken: string) => {
return new Uppy(uppyConfig).use(XHR, {
endpoint: getUploadUrl(),
withCredentials: true,
headers: {
Authorization: `Bearer ${newToken}`,
},
});
};
const [uppy, setUppy] = useState<Uppy>(getUppy(authToken));
Solution
Add an async getUploadParameters
on XHR upload, similar to what S3 plugin is doing
Alternatives
Open for alternatives but can't think of anything other than making the above code slightly nicer with some auto revalidator instead of a useEffect hook
Hi, you can also do this and not destroy the instance:
useEffect(() => {
uppy.getPlugin('XHRUpload').setOptions({
headers: {
Authorization: `Bearer ${token}`,
}
})
}, [token]);
The problem then is that it isn't retried. With tus you can do this:
import Uppy from '@uppy/core';
import Tus from '@uppy/tus';
new Uppy().use(Tus, {
endpoint: '',
async onBeforeRequest(req) {
const token = await getAuthToken();
req.setHeader('Authorization', `Bearer ${token}`);
},
onShouldRetry(err, retryAttempt, options, next) {
if (err?.originalResponse?.getStatus() === 401) {
return true;
}
return next(err);
},
async onAfterResponse(req, res) {
if (res.getStatus() === 401) {
await refreshAuthToken();
}
},
});
Ideally this would be consistent between uploaders.
yeah onBeforeRequest
is exactly what I had in mind. I'll try this one out for now, thanks
Closing this in favor of the mentioned issue.
I just saw this in the codebase:
uppy/packages/@uppy/xhr-upload/src/index.ts
Lines 417 to 426 in 5004e84
So my useEffect
suggestion in #5042 (comment) should be sufficient for now.