如何在JavaScript中跨域获取并利用服务器响应码
问题描述
我了解JS跨域限制,原本以为没法实现需求,但控制台能看到资源的404/200响应码。现在要开发一个视频播放器原型,需按优先级依次尝试加载多个备选文件:当前文件可用就播放,不可用则尝试下一个。
最初尝试用XMLHttpRequest(),但无法在.open()后加入if/else逻辑;后来改用jQuery的.ajax(),在error回调中嵌套请求,部分逻辑能运行,但遇到Access-Control-Allow-Origin错误,不过控制台能返回有效的200/404状态码。想知道如何把这些状态码整合到加载逻辑中。
当前代码:
function getSermonVideo() { "use strict"; const params = new URLSearchParams(document.location.search); const filename = params.get("filename"); const site = params.get("site"); let date = params.get("date"); let shortdate = date.slice(2); shortdate = shortdate.replaceAll("-", ""); const editedvideourl = "https://flcmedia.org/productvideo/"; const editedaudiourl = "https://flcmedia.org/product/"; let uneditedurl = "https://flcmedia.org/" + site + "/"; jQuery.ajax({ url:editedvideourl + filename + ".mp4", type:'HEAD', error: function() { jQuery.ajax({ url:editedvideourl + filename + "_480.mp4", type:'HEAD', error: function() { jQuery.ajax({ url:editedaudiourl + filename + ".mp3", type:'HEAD', error: function() { jQuery.ajax({ url: uneditedurl + "MP4/" + date.slice(0, 4) + "/" + shortdate + "Video.mp4", type:'HEAD', error: function() { jQuery.ajax({ url: uneditedurl + "MP3/" + date.slice(0, 4) + "/" + shortdate + "Audio.mp3", type:'HEAD', error: function() { //console.log("No file exists."); }, success: function() { videoplayer.src = uneditedurl + "MP3/" + date.slice(0, 4) + "/" + shortdate + "Audio.mp3" } }); }, success: function() { videoplayer.src = uneditedurl + "MP4/" + date.slice(0, 4) + "/" + shortdate + "Video.mp4" } }); }, success: function() { videoplayer.src = editedaudiourl + filename + ".mp3"; } }); }, success: function() { videoplayer.src = editedvideourl + filename + "_480.mp4"; } }); }, success: function() { videoplayer.src = editedvideourl + filename + ".mp4"; } }); }
Edge控制台输出:
Access to XMLHttpRequest at 'https://flcmedia.org/productvideo/1214-GodsIncorruptibleWordSeed-01-HisWordIsMedicine.mp4' from origin 'https://anti-exe.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. HEAD https://flcmedia.org/productvideo/1214-GodsIncorruptibleWordSeed-01-HisWordIsMedicine.mp4 net::ERR_FAILED 200 (OK) Access to XMLHttpRequest at 'https://flcmedia.org/productvideo/1214-GodsIncorruptibleWordSeed-01-HisWordIsMedicine_480.mp4' from origin 'https://anti-exe.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. HEAD https://flcmedia.org/productvideo/1214-GodsIncorruptibleWordSeed-01-HisWordIsMedicine_480.mp4 net::ERR_FAILED 404 (Not Found) Access to XMLHttpRequest at 'https://flcmedia.org/product/1214-GodsIncorruptibleWordSeed-01-HisWordIsMedicine.mp3' from origin 'https://anti-exe.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. HEAD https://flcmedia.org/product/1214-GodsIncorruptibleWordSeed-01-HisWordIsMedicine.mp3 net::ERR_FAILED 200 (OK) Access to XMLHttpRequest at 'https://flcmedia.org/FLCSarasota/MP4/2017/171126Video.mp4' from origin 'https://anti-exe.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. HEAD https://flcmedia.org/FLCSarasota/MP4/2017/171126Video.mp4 net::ERR_FAILED 200 (OK) Access to XMLHttpRequest at 'https://flcmedia.org/FLCSarasota/MP3/2017/171126Audio.mp3' from origin 'https://anti-exe.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. HEAD https://flcmedia.org/FLCSarasota/MP3/2017/171126Audio.mp3 net::ERR_FAILED 200 (OK) Access to fetch at 'https://flcmedia.org/productvideo/1214-GodsIncorruptibleWordSeed-01-HisWordIsMedicine.mp4' from origin 'https://anti-exe.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled. GET https://flcmedia.org/productvideo/1214-GodsIncorruptibleWordSeed-01-HisWordIsMedicine.mp4 net::ERR_FAILED 200 (OK)
解决方案
1. 放弃AJAX HEAD请求,直接通过媒体元素验证可用性(最优方案)
<video>/<audio>元素加载跨域资源不受CORS限制(只要服务器没设置X-Frame-Options或Content-Security-Policy禁止嵌入),直接创建临时媒体元素尝试加载,通过loadedmetadata事件判断成功,error事件判断失败,完全绕开CORS问题。
优化后的代码:
async function getSermonVideo() { "use strict"; const params = new URLSearchParams(document.location.search); const filename = params.get("filename"); const site = params.get("site"); const date = params.get("date"); const shortdate = date.slice(2).replaceAll("-", ""); // 按优先级生成候选资源列表 const candidateUrls = [ `https://flcmedia.org/productvideo/${filename}.mp4`, `https://flcmedia.org/productvideo/${filename}_480.mp4`, `https://flcmedia.org/product/${filename}.mp3`, `https://flcmedia.org/${site}/MP4/${date.slice(0, 4)}/${shortdate}Video.mp4`, `https://flcmedia.org/${site}/MP3/${date.slice(0, 4)}/${shortdate}Audio.mp3` ]; // 封装验证资源的函数 async function checkUrl(url) { return new Promise((resolve) => { const media = url.endsWith('.mp4') ? document.createElement('video') : document.createElement('audio'); media.src = url; media.preload = 'metadata'; // 加载成功 media.addEventListener('loadedmetadata', () => { media.remove(); resolve(url); }); // 加载失败 media.addEventListener('error', () => { media.remove(); resolve(null); }); }); } // 依次尝试每个资源 for (const url of candidateUrls) { const validUrl = await checkUrl(url); if (validUrl) { videoplayer.src = validUrl; return; } } // 所有资源都不可用的处理 console.log("No valid media file found."); }
2. 若坚持用AJAX,添加no-cors模式(可靠性较低)
这种方式无法读取响应状态码,只能通过请求是否触发错误间接判断,但受CORS限制,即使资源存在也会触发错误,因此不如直接加载媒体元素可靠。修改jQuery.ajax配置示例:
jQuery.ajax({ url: editedvideourl + filename + ".mp4", type: 'HEAD', crossDomain: true, xhrFields: { withCredentials: false }, // 后续回调逻辑... });
3. 避免回调地狱
不管用哪种方式,都应该用Promise/async-await代替嵌套回调,让代码更易读维护,上面的优化代码已经用async-await和循环彻底解决了嵌套问题。
内容的提问来源于stack exchange,提问作者doubleJ
相关产品推荐
相关产品推荐

