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

Ajax下载XML文件始终进入错误回调,求排查解决

问题描述

基于.NET WebAPI搭建接口处理Ajax请求:请求异常时返回含错误信息的JSON,成功则返回XML文件供下载。目前JSON错误响应可正常展示服务端错误信息,API能生成并返回文件(Postman测试可获取XML文件),但浏览器中发起Ajax请求时,本该接收文件的场景始终进入错误回调且err参数为空,无法触发文件下载,求问题原因及解决办法。

AJAX代码

let formData = {
    SomeData: { 'validation':'stuff' },
    Token: m_securityToken
};

$.ajax( {
    url: m_APIURL',
    method: 'POST', type: 'POST',
    data: JSON.stringify( formData ),
    contentType: 'application/json',
    xhrFields: { responseType: 'blob' },
    crossDomain: true,
    success: function( blob, status, xhr )
    {
        var disposition = xhr.getResponseHeader( 'Content-Disposition' );
        if( disposition && disposition.indexOf( 'attachment' ) !== -1 )
        {
            // 成功返回文件时触发下载
            var filename = 'response.xml';
            if( typeof window.navigator.msSaveBlob !== 'undefined' )
            {
                // IE兼容处理
                window.navigator.msSaveBlob( blob, filename );
            }
            else
            {
                var URL = window.URL || window.webkitURL;
                var downloadUrl = URL.createObjectURL( blob );
                var a = document.createElement( "a" );
                if( typeof a.download === 'undefined' )
                {
                    // Safari兼容处理
                    window.location.href = downloadUrl;
                }
                else
                {
                    a.href = downloadUrl;
                    a.download = filename;
                    document.body.appendChild( a );
                    a.click();
                }
                setTimeout( function() { URL.revokeObjectURL( downloadUrl ); }, 100 );
            }
        }
        else
        {
            // 验证失败返回JSON时展示错误
            if( blob != null )
            {
                if( ( blob.ErrorMessage && blob.ErrorMessage != "OK" ) || ( !blob.Content || blob.Content == '' ) )
                {
                    alert( "获取许可证文件失败:" + blob.ErrorMessage );
                }
                else
                {
                    alert( "获取许可证文件失败:" + blob.Content );
                }
            }
            else
            {
                alert( "获取许可证文件失败。" );
            }
        }
    },
    error: function( err )
    {
        if( err != null && err.length > 0 )
        {
            console.log( "响应错误:" + JSON.stringify( err ) );
        }
        else
        {
            // 总是进入这个分支
            console.log( "响应错误但未返回任何信息。" );
        }
    }
} );

API代码

[HttpPost, Route( "MyAPI/GetXMLFile" )]
public IHttpActionResult GetXMLFile( CustomRequestModel requestModel )
{
    // 请求验证
    if( !requestModel.IsValid() )
    {
        responseModel.ErrorMessage = "无效请求。";
        return Json( responseModel );
    }
    
    // 生成XML响应内容
    string rawResponseXML = CreateResponse( requestModel );
    
    // 返回文件
    HttpResponseMessage responseFile = new HttpResponseMessage( HttpStatusCode.OK );
    responseFile.Content = new StringContent( rawReponseXML );
    responseFile.Content.Headers.ContentType = new MediaTypeHeaderValue( "application/octet-stream" );
    responseFile.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue( "attachment" );
    responseFile.Content.Headers.ContentDisposition.FileName = "response.xml";
    return ResponseMessage( responseFile );
}

问题原因及解决办法

1. 跨域响应头暴露问题

因为开启了crossDomain: true,跨域请求时浏览器会限制非简单响应头的获取,Content-Disposition属于此类。需要在WebAPI的CORS配置中允许暴露该头:

// 在Startup.cs的CORS配置中添加
app.UseCors(builder => builder
    .AllowAnyOrigin() // 建议根据实际业务调整,避免过度开放
    .AllowAnyMethod()
    .AllowAnyHeader()
    .WithExposedHeaders("Content-Disposition"));

2. Blob转JSON的错误处理逻辑

设置responseType: 'blob'后,JSON错误响应也会被转为Blob,无法直接读取属性,需手动转成JSON:
修改AJAX的success回调中错误处理部分:

else {
    // 将Blob转换为JSON解析错误信息
    const reader = new FileReader();
    reader.onload = function() {
        const errorData = JSON.parse(reader.result);
        if (errorData.ErrorMessage && errorData.ErrorMessage !== "OK" || !errorData.Content || errorData.Content === '') {
            alert("获取许可证文件失败:" + errorData.ErrorMessage);
        } else {
            alert("获取许可证文件失败:" + errorData.Content);
        }
    };
    reader.readAsText(blob);
}

3. API响应内容编码修正

使用StringContent返回XML时,指定UTF-8编码避免乱码,同时修正代码中的拼写错误(rawReponseXML改为rawResponseXML):

responseFile.Content = new StringContent(rawResponseXML, Encoding.UTF8, "application/octet-stream");

4. 排查错误回调触发根源

打开浏览器开发者工具的Network面板,查看实际响应的状态码、响应头是否正常,是否有CORS相关报错。常见触发错误回调的原因包括:

  • 跨域响应头未正确配置
  • 响应MIME类型与responseType不兼容
  • 服务端实际返回了非2xx状态码(比如500错误)

内容的提问来源于stack exchange,提问作者Trint

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 15:15:53