Ajax post JSON 数据到 MVC 获取错误意外令牌 P

Ajax post JSON data to MVC getting error Unexpected token P

这让我抓狂。我有一个页面,我需要在其中为控制器制作一个 JSON post,它将处理它并 return 一个 excel 文件以供下载。到目前为止它似乎 运行 是正确的,但是当它 return 到 ajax 调用时,我得到一个解析错误和消息 "Unexpected token P." 我已经尝试了很多不同的配置和调用方法(标准 MVC ActionRequest 到 WebApi post)和它们的 none 发生了变化。这是我的代码 运行.

JavaScript:

       var treatmentplan = {"PlanRecordStatusId":"1","PlanRecordDateBegin":"","PlanRecordDateEnd":"","ClientClaimNumber":"","PatientNumber":0,"requestAction":3};

        $.ajax({
            //global: true,
            //url: '/home/ExcelRpt',
            url: '/api/TreatmentPlanExcel',
            type: 'POST',
            dataType: 'json',
            data: treatmentplan,
            //contentType: 'application/json; charset=utf-8',
            success: function (data) {
                //var msg = data.Message;
                //$('#results').html(msg);
                $("#tmpFrame").attr('src', 'URL-TO-EXCEL-FILE');
            }
            , error: function (jqXHR, exception, error) {
                if (jqXHR.status === 0) {
                    alert('Not connect.n Verify Network.');
                } else if (jqXHR.status == 404) {
                    alert('Requested page not found. [404]');
                } else if (jqXHR.status == 500) {
                    alert('Internal Server Error [500].');
                } else if (exception === 'parsererror') {
                    alert('Requested JSON parse failed.');
                } else if (exception === 'timeout') {
                    alert('Time out error.');
                } else if (exception === 'abort') {
                    alert('Ajax request aborted.');
                } else {
                    alert('Uncaught Error.n' + jqXHR.responseText);
                }
                $('#log').html(error.message);
            }
        });

这是 C# 代码(WebApi 和 MVC 控制器版本),我不打算包括我的 ToExcel 扩展,我知道这部分是有效的,只是在需要时下载它return编辑。它到达此代码,生成数据并 returning。我只需要看看到底发生了什么。如果有首选的调用方式,请告诉我(WebApi 或 MVC)

C#

Web Api 版本

    public HttpResponseMessage Post(TreatmentPlanRequest tpRequest) {
        tpRequest.Verify();
        List<TreatmentPlan> tpl = DataAccess.GetReportDap(tpRequest).ToList();

        HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
        var contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        var package = tpl.ToExcel("TreatmentReport");
        var fileStream = new MemoryStream();
        package.SaveAs(fileStream);
        fileStream.Position = 0;

        result.Content = new StreamContent(fileStream);
        result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");

        return result;

    }

这里是 MVC 控制器版本

    [HttpPost]
    public ActionResult ExcelRpt(TreatmentPlanRequest tpRequest) {
        tpRequest.Verify();            
        List<TreatmentPlan> tpl = DataAccess.GetReportDap(tpRequest).ToList();

        var contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        var package = tpl.ToExcel("TreatmentReport");
        var fileStream = new MemoryStream();
        package.SaveAs(fileStream);
        fileStream.Position = 0;

        var fsr = new FileStreamResult(fileStream, contentType);
        fsr.FileDownloadName = "TreatmentReport";

        return fsr;


    }

从这里开始,我不知道为什么这不起作用。我在 Google 上搜索了关于如何在 MVC 中执行此操作的高低搜索(我曾经使用 Web 表单执行此操作并且从未遇到过问题)。我猜我的问题出在 return 或

更改您的 Success 方法以使用 URL 打开新的 window 而不是在当前 window.

中设置框架

所以这个:

$("#tmpFrame").attr('src', 'URL-TO-EXCEL-FILE');

变为:

window.open('URL-TO-EXCEL-FILE');

在绝大多数情况下,这应该完全符合您的要求。有时,根据特定的浏览器设置,用户可能会收到 "Popup Blocked" 消息,但在我使用过的应用程序中,这种情况很少发生。

编辑:

经过补充说明,还有第二个问题。从服务器返回的数据的格式必须与 .ajax() 方法所期望的格式相同,在本例中为 'JSON'。尝试返回一个 JSON 对象,而不是从你的 Action 返回一个 FileStreamResult,它有你需要调用的 URL 来生成 Excel 文件。

return Json(new { URL = 'URL-TO-EXCEL-FILE' });

然后,按照我原来回复中的建议进行操作。

感谢 Kris Hatcher 提供的解决方案。他建议制作两个 ActionResults。一种根据初始请求的参数构建查询字符串的方法。它 return 是一个完整的 URL 参数。然后它使用 returned url.

执行 Window.Open()

在我找到的所有示例中,这是唯一适合我的示例。下面是代码的工作原理。

JavaScript:

function TestWebApiReport() {
    var reportData = GetReport();

    $.ajax({
        url: '/home/ExcelResults'
        , data: reportData
        , type: 'POST'
        , dataType: 'json'
        , success: function (data) {
            window.open(data.URL);
        }, error: function (jqXHR, exception, error) {
            alert("GRRRRRR!!!")
        }
    });
}

它创建 JSON 数据,然后将其发布到 JsonResult。这是控制器代码。

C#

    [HttpPost]
    public JsonResult ExcelResults(ReportRequest tpRequest) {
        StringBuilder sb = new StringBuilder();
        bool firstIn = true;
        sb.AppendFormat("{0}/Home/ExcelRpt", Request.Url.Scheme + "://" + Request.Url.Authority);
        foreach (var prop in tpRequest.GetType().GetProperties()) {
            if (prop.GetValue(tpRequest, null) != null) {
                if (firstIn) {
                    sb.AppendFormat("?");
                    firstIn = false;
                } else {
                    sb.AppendFormat("&");
                }
                sb.AppendFormat("{0}={1}", prop.Name, prop.GetValue(tpRequest, null));
            }
        }

        return Json(new { URL = sb.ToString() }); 
    }

您返回 JavaScript,您会看到 return 数据使用 URL 执行 Window.Open()。然后创建 excel 文件。这是最后一次调用 (ActionResult)。

    [HttpGet]
    public ActionResult ExcelRpt(ReportRequest tpRequest) {

        if (tpRequest.requestAction != RequestAction.Report) {
            throw new Exception("Did not use action request type of 'Report'.");
        }
        tpRequest.requestAction = RequestAction.Report;
        List<Report> tpl = DataAccess.GetReportDap(tpRequest).ToList();

        var contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        var package = tpl.ToExcel("Report");
        var fileStream = new MemoryStream();
        package.SaveAs(fileStream);
        fileStream.Position = 0;

        var fsr = new FileStreamResult(fileStream, contentType);
        fsr.FileDownloadName = "TreatmentReport.xlsx";

        return fsr;
    }

ReportRequest 是一个 class 我有 ToExcel(),我扩展了列表项。现在效果很好。