Skip to content

Commit 063188b

Browse files
committed
fix: improve song download process by handling S3 redirects
- Updated the song loading logic in EditSongProvider to handle backend redirects when fetching song files. - Implemented error handling for redirect responses to extract the S3 signed URL. - Enhanced the file fetching process by using the native fetch API for better CORS handling. - Improved error messages for various failure scenarios during the song download process.
1 parent dcbd879 commit 063188b

File tree

1 file changed

+45
-8
lines changed

1 file changed

+45
-8
lines changed

apps/frontend/src/modules/song-edit/components/client/context/EditSong.context.tsx

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -237,15 +237,51 @@ export const EditSongProvider = ({
237237
const token = getTokenLocal();
238238

239239
try {
240-
const songFile = (
240+
// The backend redirects (302) to an S3 signed URL
241+
// Get the redirect URL first, then fetch from S3 directly
242+
let s3Url: string | null = null;
243+
244+
try {
245+
// Make request without following redirects to get the S3 URL
241246
await axiosInstance.get(`/song/${id}/download`, {
242247
params: {
243248
src: 'edit',
244249
},
245-
responseType: 'arraybuffer',
246250
headers: { authorization: `Bearer ${token}` },
247-
})
248-
).data as ArrayBuffer;
251+
maxRedirects: 0, // Don't follow redirects
252+
validateStatus: () => false, // Don't throw on any status
253+
});
254+
} catch (redirectError: any) {
255+
// Axios throws an error when maxRedirects is 0 and a redirect occurs
256+
// Extract the Location header from the redirect response
257+
if (
258+
redirectError.response?.status >= 300 &&
259+
redirectError.response?.status < 400
260+
) {
261+
s3Url = redirectError.response.headers.location;
262+
if (!s3Url) {
263+
throw new Error('Redirect received but no Location header found');
264+
}
265+
} else {
266+
// Not a redirect error, re-throw it
267+
throw redirectError;
268+
}
269+
}
270+
271+
if (!s3Url) {
272+
throw new Error('Failed to get song download URL from redirect');
273+
}
274+
275+
// Fetch the file directly from S3 using native fetch (handles CORS better)
276+
const s3Response = await fetch(s3Url);
277+
if (!s3Response.ok) {
278+
throw new Error(
279+
`Failed to fetch song from storage: ${s3Response.status} ${s3Response.statusText}`,
280+
);
281+
}
282+
283+
const arrayBuffer = await s3Response.arrayBuffer();
284+
const songFile = arrayBuffer;
249285

250286
// convert to song
251287
const song = await parseSongFromBuffer(songFile);
@@ -264,16 +300,17 @@ export const EditSongProvider = ({
264300
if (error.response) {
265301
// Server responded with an error status
266302
errorMessage =
267-
error.response.data.message ||
268-
Object.values(error.response.data.error || {})[0] ||
303+
error.response.data?.message ||
304+
(error.response.data?.error
305+
? Object.values(error.response.data.error)[0]
306+
: null) ||
269307
`Failed to load song: ${error.response.status}`;
270308
} else if (error.request) {
271-
console.error('Error loading song', error);
272309
// Request was made but no response received (network error)
273310
errorMessage =
274311
'Network error: Unable to connect to the server. Please check your internet connection and try again.';
275312
} else {
276-
// Something else happened
313+
// Something else happened (including fetch errors)
277314
errorMessage = error.message || errorMessage;
278315
}
279316

0 commit comments

Comments
 (0)