'Frontend JavaScript request gets 302-redirected but ultimately fails

I'm trying to create an audio visualization for a podcast network, using the Web Audio API with createMediaElementSource() very similarly to the model explained in this tutorial. So far I've gotten it to work fine in Chrome, and you can see it here (note: click on the red box to start it).

Update: Based on discussion in the comments, it’s now become clear that the problem happens because the request gets redirected to another URL, by way of a 302 redirect.


However, Safari refuses to work, outputting no sound and producing no visualization although it shows the track playing. I believe it has to do with the CORS policy of the server I'm requesting the audio from, because I've alternatively tried using this audio source and it works great in all browsers. My suspicion is it's an issue arising due to this standard of the web audio API.

The fact that it only happens in safari makes me pray that there's some easy syntactic solution either on my end or the server host's end in their CORS policy to get this to work. I'm hoping someone can point out exactly what's going wrong in the header requests/responses that's causing this problem. Let me know if there's any more information I need to provide. I've left a simplified version of my AudioContext code below in case a problem surfaces there.

//definitions
var url='https://rss.art19.com/episodes/72a3bc7e-118a-4171-8be4-125913860ef7.mp3';
//in safari it works with the link below, but not with any art19 link such as the one above.
//https://s3-us-west-2.amazonaws.com/s.cdpn.io/858/outfoxing.mp3
var audiotag=document.querySelector('audio');
var AudioContext = window.AudioContext || window.webkitAudioContext;
var context;
var statcontext;
var analyser;
var source;
var loopf;

//on load:
context=new AudioContext();
audiotag.crossOrigin="anonymous";
audiotag.preload="none";
audiotag.src=url;
source=context.createMediaElementSource(audiotag);
analyser=context.createAnalyser();
source.connect(analyser);
analyser.connect(context.destination);
analyser.smoothingTimeConstant=0.85
analyser.fftSize = 16384;

//later, on user input(clicking on red bar):
var bufferLength = analyser.frequencyBinCount;
var dataArray = new Uint8Array(bufferLength);
function updateDisplay() {
  loopf=requestAnimationFrame(updateDisplay);
  analyser.getByteFrequencyData(dataArray);
  draw(dataArray.slice(100,150),-100,100);
}
context.resume();
audiotag.play();
updateDisplay();


Solution 1:[1]

Short answer: The maintainers of the service sending the 302 response to your request should update their backend config such that it adds the Access-Control-Allow-Origin header to 302 responses (and any other 3xx redirect responses) — not just to 200 OK responses.

If you can’t get them to do that, then basically you only have exactly two other options:

  1. Change your frontend code to make the request through a CORS proxy; or else
  2. Don’t make the request from your frontend code at all, but instead do it completely from your backend server-side code (where the same-origin policy doesn’t apply).

Explanation

Here’s what happens:

  1. Your frontend code makes a request to a https://rss.art19.com/episodes/….mp3 URL.

  2. The https://rss.art19.com server replies to with a 302 redirect response that has a Location: https://content.production.cdn.art19.com/…episodes/….mp3 header.

  3. The browser receives that 302 response and checks the response headers to see if there’s an Access-Control-Allow-Origin header. If there isn’t, the browser blocks your code from accessing the response from the https://content.production.cdn.art19.com/….mp3 redirect URL. Instead the browser will stop and throw an exception.

You can sometimes fix this problem by taking the redirect URL and using it as the request URL in your frontend code. For example, rather than using https://rss.art19.com/episodes/….mp3 in your code, use https://content.production.cdn.art19.com/…episodes/….mp3 — since the 200 OK response from that includes the Access-Control-Allow-Origin header).

But in many or most cases in practice, that strategy won’t work — because it’s not feasible to preemptively identify what the redirect URL will be.

Note: by design, browsers by design don’t expose redirects to frontend code. So it’s impossible from frontend code to programatically get a redirect URL and do another request with it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1