'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:
- Change your frontend code to make the request through a CORS proxy; or else
- 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:
Your frontend code makes a request to a
https://rss.art19.com/episodes/….mp3
URL.The
https://rss.art19.com
server replies to with a302
redirect response that has aLocation: https://content.production.cdn.art19.com/…episodes/….mp3
header.The browser receives that
302
response and checks the response headers to see if there’s anAccess-Control-Allow-Origin
header. If there isn’t, the browser blocks your code from accessing the response from thehttps://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 |