You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 21:08:09