【问题标题】:Why is my ajax post being truncated?为什么我的 ajax 帖子被截断?
【发布时间】:2017-06-13 10:00:18
【问题描述】:

我刚刚更新了我的 mvc 服务以包含更大的错误和日志记录。我现在已经多次遇到这个确切的错误。但无法复制。

Unterminated string. Expected delimiter: ". Path 'Breadcrumbs[18].Params', line 1, position 59740. at Newtonsoft.Json.JsonTextReader.ReadStringIntoBuffer(Char quote) at 

路径每次都不同,具体取决于用户向服务器发送的内容。

我的 ajax 请求通常如下所示:

$.ajax(myURL("SendBreadcrumbs"), {
            type: "POST",
            cache: false,
            data: { telemetry: telemetry.JSONify(), userID: currentUser, isMyVI: isMyVI }
        })

在这些情况下,userID 和 isMyVI(布尔值)不存在,遥测字符串被截断。

JSONify方法如下:

self.JSONify = function () {
    var data = ko.mapping.toJSON(self, TelemetryMapping);
    return data;
}

这是 knockoutJSs 序列化程序。

服务器端:

public void SendBreadcrumbs(string telemetry, string userID = null, bool isMyVI = true)
{
    MyServiceAudit audit;
    Guid UserID;
    if (Guid.TryParse(userID, out UserID))
        audit = InsertAudit(UserID);
    else
        audit = InsertAudit(null);
    try
    {
        Models.Telemetry data = JsonConvert.DeserializeObject<Models.Telemetry>(telemetry);
        Controllers.Telemetry.UpdateTelemetry(data, isMyVI);
    }
    catch (Exception ex)
    {
         MyServiceAuditDB.FailAudit(audit.ID, ex.Message + " " + ex.StackTrace);
    }
}

我完全被难住了,我尝试使用更大的最大值等更新服务器上的 web.config,以查看它在那一侧被截断。

我在我的 ajax 中唯一的其他区别是 3 分钟的全局超时。

这是否像客户端未处理特殊字符或服务器端限制一样简单,还是数据太大以至于被分块而服务器端不知道等待下一个块?

【问题讨论】:

  • 数据有多大?
  • 它只要一根字符串tbh。我在反序列化等(HttpContext.Request.Params.ToString())之前记录了http参数。那么其中一个失败的请求是 117,454 个字符长?
  • 也刚刚检查过我有这个大小的参数 3,119,214。哪个没有失败?那么我可以排除因大小而截断的情况吗?
  • 只是一个关于您的异常处理的 FYI。如果您执行ex.ToSring(),您将收到消息、堆栈跟踪以及所有内部异常。根据异常,内部异常实际上是您想要帮助解决问题的。
  • 谢谢,我会记下来的。

标签: c# jquery ajax iis knockout.js


【解决方案1】:

在几个 cmets 的帮助下,回答并最终获得实时失败数据,我能够解决这个问题。

事实证明,不仅用户使用了特殊字符,而且发送下来的一些静态数据也包含了这个(GIGO - 无法相信我们某些数据的状态)。

客户端解决方案:

encodeURIComponent() 函数对 URI 组件进行编码。 此函数对特殊字符进行编码。此外,它还对以下字符进行编码: , / ? : @ & = + $ #

$.ajax(myURL("SendBreadcrumbs"), {
        type: "POST",
        cache: false,
        data: { telemetry: encodeURIComponent(telemetry.JSONify()), userID: currentUser, isMyVI: isMyVI }
    })

服务器端解决方案:

将字符串转换为其非转义表示。 Uri.UnescapeDataString()

public void SendBreadcrumbs(string telemetry, string userID = null, bool isMyVI = true)
{
    MyServiceAudit audit;
    Guid UserID;
    if (Guid.TryParse(userID, out UserID))
        audit = InsertAudit(UserID);
    else
        audit = InsertAudit(null);
    try
    {
        Models.Telemetry data = JsonConvert.DeserializeObject<Models.Telemetry>(Uri.UnescapeDataString(telemetry));
        Controllers.Telemetry.UpdateTelemetry(data, isMyVI);
    }
    catch (Exception ex)
    {
         MyServiceAuditDB.FailAudit(audit.ID, ex.Message + " " + ex.StackTrace);
    }
}

Web 应用程序配置:

由于尝试发送 20 封电子邮件,我有一个用户收到 500 错误。我更新了配置以包括最大请求长度(以千字节为单位,例如为 1GB)和最大内容长度(以字节为单位,例如为 1GB)。电子邮件没有问题。简直不敢相信!

<appSettings>
    <add key="aspnet:MaxJsonDeserializerMembers" value="150000" />
</appSettings>
<system.web>
    <httpRuntime targetFramework="4.5" maxQueryStringLength="32768" maxUrlLength="65536" maxRequestLength="1048576" />
</system.web>
<system.webServer>
    <security>
        <requestFiltering>
            <requestLimits maxQueryString="32768" maxAllowedContentLength="1073741824"  />
        </requestFiltering>
    </security>
</system.webServer>
<system.web.extensions>
    <scripting>
        <webServices>
            <jsonSerialization maxJsonLength="2147483647" />
        </webServices>
    </scripting>
</system.web.extensions>

【讨论】:

    【解决方案2】:

    我建议您使用 fiddler 粗略了解实际发送的数据。这肯定是反序列化的问题,您的代码看起来完全没问题。数据的大小在这里应该不是问题,获取一些原始数据视图,你应该没问题。

    还要查看 JSONify() 是否返回格式正确的数据而不转义字符序列。

    【讨论】:

      【解决方案3】:

      尝试对用户输入的内容使用 encodeURIComponent。

      【讨论】:

        【解决方案4】:

        您没有指定您使用的是哪个版本的 jQuery,但是当我们假设一个稳定的版本时,我们可以确定$.ajax() 下线中必要的编码和转义是完美的。

        如果请求长度是原因,我们会在客户端看到一个 http 错误并且没有调用服务器端函数(“超出最大请求长度”)。您的观察结果支持了这一点,即具有较长字符串的请求可以成功,而较短的字符串可能会失败。

        我建议采取两种行动:

        1) 为减少碎片化、分层和可能的误导性诊断,请勿仅对遥测数据进行 JSON 化。从遥测、userID 和 isMyVi 构建您的对象,然后将 that 作为一个整体进行 JSONify(这意味着,如果可能,将元数据包含在 TelemetryMapping 描述中)

        2) 在运行时客户端检查telemetry.JSONify() 的值。如果你发现截断是由这个引起的,重点关注knockoutJS的版本和完整性,或者更换。正如@Destrif 在他们的评论中指出的那样,https://stackoverflow.com/a/21565447/1132334 表明,转义双引号、反斜杠和斜杠可能不是 knockoutJS 任务的一部分 -

        这可能就像将调用包装在另一个 escape() 中一样简单:

        self.JSONify = function () {
            var data = escape(ko.mapping.toJSON(self, TelemetryMapping));
            return data;
        }
        

        【讨论】:

        • escape() 函数在 JavaScript 1.5 版中已弃用。请改用 encodeURI() 或 encodeURIComponent()。
        猜你喜欢
        • 2012-09-09
        • 2020-08-02
        • 2010-12-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多