Почему мой пост ajax усечен?
Я только что обновил мою службу 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 (boolean) не существовали и строка телеметрии усекается.
Метод JSONify выглядит следующим образом:
self.JSONify = function () {
var data = ko.mapping.toJSON(self, TelemetryMapping);
return data;
}
Это сериализатор нокаута.
Сторона сервера:
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 на сервере с большими значениями max и т.д., чтобы увидеть его усечение с этой стороны.
Единственное отличие, которое у меня есть в моем ajax, - глобальный тайм-аут 3 минут.
Является ли это так же просто, как специальные символы, которые не обрабатываются на стороне клиента или ограничения на стороне сервера, или данные настолько велики, что они становятся фрагментированными, а серверная сторона не знает, ждать следующего фрагмента?
Ответы
Ответ 1
С помощью нескольких комментариев, ответов и, наконец, получивших живые неудачные данные, я смог это разрешить.
Оказалось, что пользователь не только использовал специальные символы, но и некоторые из статических данных, отправленных вниз, включали это (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);
}
}
Конфигурация веб-приложения:
У меня был пользователь, получивший 500 ошибок, из-за попытки отправить 20 писем. Я обновил конфигурацию, чтобы включить максимальную длину запроса (в килобайтах, пример - 1 ГБ) и максимальную длину содержимого (в байтах, пример - 1 ГБ). Письма не возникли. Не мог в это поверить!
<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
Я предлагаю вам использовать скрипач для получения приблизительного представления о том, какие данные действительно отправлены. Несомненно, проблема де-сериализации и ваш код выглядит полностью. Размер данных не должен быть проблемой здесь, получить некоторое представление данных, и вы должны быть в порядке.
Также проверьте, правильно ли вернули данные в формате JSONify(), не избегая последовательности символов.
Ответ 3
Попробуйте использовать encodeURIComponent для содержимого, введенного пользователем.
Ответ 4
Вы не укажете, какую версию jQuery вы используете, но когда мы предполагаем стабильную версию, мы можем быть уверены, что необходимая кодировка и экранирование в нижней строке $.ajax()
безупречны.
Если причиной была длина запроса, мы увидели бы ошибку HTTP на стороне клиента и не вызывали бы серверную функцию ( "максимальная длина запроса превышена" ). Это подтверждается вашим наблюдением, что запросы с более длинными строками могут преуспеть, в то время как более короткие могут выйти из строя.
Я бы предложил два действия:
1) Чтобы уменьшить фрагментацию, расслоение и возможные вводящие в заблуждение диагнозы, не используйте JSONify только телеметрию. Постройте объект из телеметрии, userID и isMyVi, затем JSONify, что в целом (это означает, что, если возможно, включите метаданные в TelemetryMapping
)
2) Проверьте значение telemetry.JSONify()
во время выполнения на стороне клиента. Если вы обнаружите, что это усечение вызвано этим, сосредоточьтесь на версии и целостности нокаутаJS или замените. Как отмечает @Destrif в своем комментарии, fooobar.com/info/386880/... предполагает, что он не может быть частью задач knockoutJS, чтобы избежать двойных кавычек, обратных косых черт и косых черт -
который может быть таким же простым, как перенос вызова в другой escape()
:
self.JSONify = function () {
var data = escape(ko.mapping.toJSON(self, TelemetryMapping));
return data;
}