장애/오류 발생 시 JSON 서비스가 반환해야 할 항목
C#(.ashx 파일)에 JSON 서비스를 쓰고 있습니다.서비스에 대한 요청이 성공하면 JSON 데이터를 반환합니다.예외가 발생했거나(데이터베이스 타임아웃 등) 요구가 잘못되었거나(데이터베이스에 존재하지 않는 ID가 인수로 지정됨 등) 요청이 실패했을 경우 서비스는 어떻게 응답해야 합니까?적절한 HTTP 상태 코드는 무엇입니까?데이터가 있는 경우 반환해야 합니다.
서비스는 주로 jQuery.form 플러그인을 사용하여 jQuery에서 호출될 것으로 예상됩니다.jQuery 또는 이 플러그인은 오류 응답을 처리하는 기본 방법이 있습니까?
편집: 성공 시 jQuery + .ashx + HTTP [ status codes ]를 사용하기로 결정했습니다.JSON을 반환하지만 오류가 발생하면 jQuery.ajax의 오류 옵션에서 원하는 문자열이 반환됩니다.
상황에 맞는 베스트 프랙티스에 대한 자세한 내용은 이 질문을 참조하십시오.
(상기 링크로부터의) topline 제안에서는 핸들러가 찾고 있는 응답 구조(성공과 실패 모두)를 표준화하여 서버 레이어에서 모든 예외를 검출하여 동일한 구조로 변환하는 것입니다.예: (이 답변에서):
{
success:false,
general_message:"You have reached your max number of Foos for the day",
errors: {
last_name:"This field is required",
mrn:"Either SSN or MRN must be entered",
zipcode:"996852 is not in Bernalillo county. Only Bernalillo residents are eligible"
}
}
에는 스택오버플로우가 있습니다(하다). 투표와 같은 쓰기 조작은"Success" ★★★★★★★★★★★★★★★★★」"Message"여부에 관계없이
{ Success:true, NewScore:1, Message:"", LastVoteTypeId:3 }
@Phil로.H씨는 무엇을 선택하든 일관성이 있어야 한다고 지적했다.이것은 말하기는 쉽지만 실행하기는 어렵다(개발 중인 모든 것과 마찬가지로).
예를 들어 SO에 대한 의견을 너무 빨리 제출하면 일관성이 유지되고 반환되지 않습니다.
{ Success: false, Message: "Can only comment once every blah..." }
SO)를 시킵니다.HTTP 500.error콜백
jQuery +를 사용하는 것이 '적당하다고 느끼는' 만큼.ashx [ 코드] HTTP [ im im ]IMO 。를 「을 알 수 jQuery는 에러 코드를 「검출」하는 것이 아니라, 성공 코드가 없는 것에 주의해 주세요.이는 jQuery를 사용하여 http 응답 코드를 중심으로 클라이언트를 설계할 때 중요한 차이입니다.두 가지 선택지('성공'이냐 '오류'냐)만 선택할 수 있습니다.이 두 가지 선택지는 독자적으로 확장해야 합니다.적은 수의 Web Services를 사용하고 있는 경우, 페이지 수가 적은 경우는 문제가 없으나, 규모가 큰 경우는 문제가 될 수 있습니다.
.asmxHTTP 상태 코드를 커스터마이즈하는 것이 아니라 커스텀오브젝트를 반환하는 Web Service(또는 WCF).게다가 JSON 의 시리얼화는 무료로 이용하실 수 있습니다.
반환되는 HTTP 상태 코드는 발생한 오류 유형에 따라 달라야 합니다.데이터베이스에 ID가 존재하지 않는 경우 404를 반환합니다.Ajax 콜을 발신할 권한이 사용자에게 없는 경우 403을 반환하고 레코드를 찾을 수 있을 때까지 데이터베이스가 타임아웃되면 500(서버 오류)을 반환합니다.
jQuery는 이러한 오류 코드를 자동으로 검출하여 Ajax 콜에서 정의한 콜백 함수를 실행합니다.문서: http://api.jquery.com/jQuery.ajax/
의 예$.ajax류류: :
$.ajax({
type: 'POST',
url: '/some/resource',
success: function(data, textStatus) {
// Handle success
},
error: function(xhr, textStatus, errorThrown) {
// Handle error
}
});
HTTP 상태 코드를 사용하는 것은 RESTful 방법이지만, 이는 나머지 인터페이스를 리소스 URI 등을 사용하여 RESTful로 만드는 것을 권장합니다.
실제로 인터페이스를 원하는 대로 정의하십시오(예를 들어 오류가 있는 속성을 자세히 설명하는 HTML 청크 등을 반환). 그러나 프로토타입에서 동작하는 것을 결정한 후에는 무자비하게 일관성을 유지하십시오.
예외만 버블하면 'error' 옵션에 대해 전달되는 jQuery 콜백으로 처리되어야 한다고 생각합니다.(서버측의 이 예외도 중앙 로그에 기록합니다).특별한 HTTP 에러 코드는 필요 없지만, 다른 사람들도 어떻게 하는지 궁금해요.
이게 내가 하는 일이지만 그건 내 $.02일 뿐이야
RESTful이 되어 에러 코드를 반환하는 경우는, W3C 로 지정되어 있는 표준 코드(http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 에 준거해 주세요.
나는 이 문제를 푸는 데 몇 시간을 보냈다.나의 솔루션은 다음의 희망/요건에 근거하고 있습니다.
- 모든 JSON 컨트롤러 동작에서 반복적인 보일러 플레이트 오류 처리 코드를 사용하지 마십시오.
- HTTP(오류) 상태 코드를 유지합니다. 이유가 무엇입니까?높은 수준의 우려가 낮은 수준의 구현에 영향을 미쳐서는 안 되기 때문입니다.
- 서버에서 오류/예외가 발생했을 때 JSON 데이터를 얻을 수 있습니다.왜요?풍부한 에러 정보가 필요할지도 모르기 때문입니다.예를 들어 오류 메시지, 도메인별 오류 상태 코드, 스택 추적(디버깅/개발 환경).
- 사용하기 쉬운 클라이언트 측 - jQuery를 사용하는 것이 좋습니다.
HandleErrorAttribute를 만듭니다(자세한 내용은 코드 코멘트 참조).「사용법」을 포함한 몇개의 정보가 누락되어 있기 때문에, 코드가 컴파일 되지 않는 경우가 있습니다.Global.asax.cs에서 응용 프로그램 초기화 중에 필터를 글로벌필터에 추가합니다.
GlobalFilters.Filters.Add(new UnikHandleErrorAttribute());
속성:
namespace Foo
{
using System;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
/// <summary>
/// Generel error handler attribute for Foo MVC solutions.
/// It handles uncaught exceptions from controller actions.
/// It outputs trace information.
/// If custom errors are enabled then the following is performed:
/// <ul>
/// <li>If the controller action return type is <see cref="JsonResult"/> then a <see cref="JsonResult"/> object with a <c>message</c> property is returned.
/// If the exception is of type <see cref="MySpecialExceptionWithUserMessage"/> it's message will be used as the <see cref="JsonResult"/> <c>message</c> property value.
/// Otherwise a localized resource text will be used.</li>
/// </ul>
/// Otherwise the exception will pass through unhandled.
/// </summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class FooHandleErrorAttribute : HandleErrorAttribute
{
private readonly TraceSource _TraceSource;
/// <summary>
/// <paramref name="traceSource"/> must not be null.
/// </summary>
/// <param name="traceSource"></param>
public FooHandleErrorAttribute(TraceSource traceSource)
{
if (traceSource == null)
throw new ArgumentNullException(@"traceSource");
_TraceSource = traceSource;
}
public TraceSource TraceSource
{
get
{
return _TraceSource;
}
}
/// <summary>
/// Ctor.
/// </summary>
public FooHandleErrorAttribute()
{
var className = typeof(FooHandleErrorAttribute).FullName ?? typeof(FooHandleErrorAttribute).Name;
_TraceSource = new TraceSource(className);
}
public override void OnException(ExceptionContext filterContext)
{
var actionMethodInfo = GetControllerAction(filterContext.Exception);
// It's probably an error if we cannot find a controller action. But, hey, what should we do about it here?
if(actionMethodInfo == null) return;
var controllerName = filterContext.Controller.GetType().FullName; // filterContext.RouteData.Values[@"controller"];
var actionName = actionMethodInfo.Name; // filterContext.RouteData.Values[@"action"];
// Log the exception to the trace source
var traceMessage = string.Format(@"Unhandled exception from {0}.{1} handled in {2}. Exception: {3}", controllerName, actionName, typeof(FooHandleErrorAttribute).FullName, filterContext.Exception);
_TraceSource.TraceEvent(TraceEventType.Error, TraceEventId.UnhandledException, traceMessage);
// Don't modify result if custom errors not enabled
//if (!filterContext.HttpContext.IsCustomErrorEnabled)
// return;
// We only handle actions with return type of JsonResult - I don't use AjaxRequestExtensions.IsAjaxRequest() because ajax requests does NOT imply JSON result.
// (The downside is that you cannot just specify the return type as ActionResult - however I don't consider this a bad thing)
if (actionMethodInfo.ReturnType != typeof(JsonResult)) return;
// Handle JsonResult action exception by creating a useful JSON object which can be used client side
// Only provide error message if we have an MySpecialExceptionWithUserMessage.
var jsonMessage = FooHandleErrorAttributeResources.Error_Occured;
if (filterContext.Exception is MySpecialExceptionWithUserMessage) jsonMessage = filterContext.Exception.Message;
filterContext.Result = new JsonResult
{
Data = new
{
message = jsonMessage,
// Only include stacktrace information in development environment
stacktrace = MyEnvironmentHelper.IsDebugging ? filterContext.Exception.StackTrace : null
},
// Allow JSON get requests because we are already using this approach. However, we should consider avoiding this habit.
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
// Exception is now (being) handled - set the HTTP error status code and prevent caching! Otherwise you'll get an HTTP 200 status code and running the risc of the browser caching the result.
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; // Consider using more error status codes depending on the type of exception
filterContext.HttpContext.Response.Cache.SetCacheability(HttpCacheability.NoCache);
// Call the overrided method
base.OnException(filterContext);
}
/// <summary>
/// Does anybody know a better way to obtain the controller action method info?
/// See http://stackoverflow.com/questions/2770303/how-to-find-in-which-controller-action-an-error-occurred.
/// </summary>
/// <param name="exception"></param>
/// <returns></returns>
private static MethodInfo GetControllerAction(Exception exception)
{
var stackTrace = new StackTrace(exception);
var frames = stackTrace.GetFrames();
if(frames == null) return null;
var frame = frames.FirstOrDefault(f => typeof(IController).IsAssignableFrom(f.GetMethod().DeclaringType));
if (frame == null) return null;
var actionMethod = frame.GetMethod();
return actionMethod as MethodInfo;
}
}
}
클라이언트 측에서 사용하기 쉽게 하기 위해 다음과 같은 jQuery 플러그인을 개발했습니다.
(function ($, undefined) {
"using strict";
$.FooGetJSON = function (url, data, success, error) {
/// <summary>
/// **********************************************************
/// * UNIK GET JSON JQUERY PLUGIN. *
/// **********************************************************
/// This plugin is a wrapper for jQuery.getJSON.
/// The reason is that jQuery.getJSON success handler doesn't provides access to the JSON object returned from the url
/// when a HTTP status code different from 200 is encountered. However, please note that whether there is JSON
/// data or not depends on the requested service. if there is no JSON data (i.e. response.responseText cannot be
/// parsed as JSON) then the data parameter will be undefined.
///
/// This plugin solves this problem by providing a new error handler signature which includes a data parameter.
/// Usage of the plugin is much equal to using the jQuery.getJSON method. Handlers can be added etc. However,
/// the only way to obtain an error handler with the signature specified below with a JSON data parameter is
/// to call the plugin with the error handler parameter directly specified in the call to the plugin.
///
/// success: function(data, textStatus, jqXHR)
/// error: function(data, jqXHR, textStatus, errorThrown)
///
/// Example usage:
///
/// $.FooGetJSON('/foo', { id: 42 }, function(data) { alert('Name :' + data.name); }, function(data) { alert('Error: ' + data.message); });
/// </summary>
// Call the ordinary jQuery method
var jqxhr = $.getJSON(url, data, success);
// Do the error handler wrapping stuff to provide an error handler with a JSON object - if the response contains JSON object data
if (typeof error !== "undefined") {
jqxhr.error(function(response, textStatus, errorThrown) {
try {
var json = $.parseJSON(response.responseText);
error(json, response, textStatus, errorThrown);
} catch(e) {
error(undefined, response, textStatus, errorThrown);
}
});
}
// Return the jQueryXmlHttpResponse object
return jqxhr;
};
})(jQuery);
이 모든 것에서 얻을 수 있는 게 뭐죠?최종 결과는 이다.
- 컨트롤러 조작 중 HandleErrorAttributes에 대한 요건은 없습니다.
- 컨트롤러 동작 중 반복적인 보일러 플레이트 오류 처리 코드가 포함되어 있지 않습니다.
- 단일 오류 처리 코드를 사용하여 로깅 및 기타 오류 처리 관련 사항을 쉽게 변경할 수 있습니다.
- 간단한 요건: JsonResult를 반환하는 컨트롤러 작업은 ActionResult와 같은 기본 유형이 아닌 반환 유형 JsonResult를 가져야 합니다.이유:FooHandleErrorAttribute의 코드 코멘트를 참조해 주세요.
클라이언트 측 예:
var success = function(data) {
alert(data.myjsonobject.foo);
};
var onError = function(data) {
var message = "Error";
if(typeof data !== "undefined")
message += ": " + data.message;
alert(message);
};
$.FooGetJSON(url, params, onSuccess, onError);
댓글은 대환영입니다!언젠가 이 솔루션에 대해 블로그에 올릴 것 같습니다.
ASP와 마찬가지로 오류 상태를 설명하는 JSON 오브젝트와 함께 500 에러를 반환할 것입니다.NET AJAX "ScriptService" 오류가 반환됩니다.나는 이것이 꽤 표준적이라고 믿는다.예기치 않은 에러 상황을 처리할 때 일관성이 유지되는 것은 매우 좋은 일입니다.
게다가 에 내장된 기능만을 사용하는 것은 어떨까요?NET, C#로 쓰면?WCF 및 ASMX 서비스를 통해 데이터를 JSON으로 쉽게 직렬화할 수 있습니다.
레일 비계 사용422 Unprocessable Entity이런 종류의 오류에 대해서요.상세한 것에 대하여는, RFC 4918 을 참조해 주세요.
예, HTTP 상태 코드를 사용해야 합니다.또한 Nottingham의 제안과 같이 다소 표준화된 JSON 형식으로 오류 설명을 반환하는 것이 좋습니다. apigility Error Reporting:
API 문제의 페이로드 구조는 다음과 같습니다.
- type: 오류 상태를 설명하는 문서의 URL(선택사항, 아무것도 제공되지 않은 경우 "about:blank"로 간주됩니다. 사람이 읽을 수 있는 문서로 해결되어야 합니다. Apigility는 항상 이를 제공합니다).
- title: 에러 상태의 간단한 제목(같은 유형의 모든 문제에 대해 동일해야 합니다.어피지빌리티는 항상 이 기능을 제공합니다).
- status: 현재 요청의 HTTP 상태 코드(옵션.어피지빌리티는 항상 이를 제공합니다).
- detail: 이 요구에 고유한 오류 상세(옵션.어피지빌리티에는 문제마다 해당 오류가 필요합니다).
- instance: 이 문제의 특정 인스턴스를 식별하는 URI(옵션.현재 Apigility는 이 인스턴스를 제공하지 않습니다).
사용자가 유효하지 않은 데이터를 제공했을 경우 해당 데이터는400 Bad Request(요구에 잘못된 구문이 포함되어 있거나 요구에 대응할 수 없습니다).
http 에러 코드는 반환하지 않는 것이 좋다고 생각합니다.이 예외는 어플리케이션의 클라이언트 엔드에 도움이 됩니다.인터페이스가 실제로 무슨 일이 일어났는지 알 수 있도록 합니다.404개의 에러 코드나 그런 성질을 가진 실제 문제를 숨기려 하지 않습니다.
서버/프로토콜 오류에 대해서는 가능한 REST/HTTP로 하겠습니다(브라우저에 URL을 입력하는 것과 비교해 보십시오).
- 존재하지 않는 항목을 (/persons/{non-existing-id-here})라고 합니다.404를 돌려줘
- 서버에서 예기치 않은 오류(코드 버그)가 발생했습니다.500을 돌려주세요.
- 클라이언트 사용자에게 리소스를 가져올 권한이 없습니다.401을 돌려주세요.
도메인/비즈니스 로직별 오류에 대해서는 프로토콜이 올바른 방식으로 사용되고 서버 내부 오류가 없으므로 JSON/XML 개체 또는 원하는 데이터로 응답하십시오(웹 사이트의 양식을 작성하는 것과 비교해 보십시오).
- 사용자가 계정 이름을 변경하려고 하지만 사용자에게 전송된 이메일의 링크를 클릭하여 계정을 아직 확인하지 않았습니다.{"error":"Account not verify"} 또는 기타 항목을 반환합니다.
- 사용자가 책을 주문하려고 하는데 책이 팔려서(DB에서 상태가 바뀌어서) 더 이상 주문할 수 없습니다.{"error":"이미 판매된 책"}을(를) 반환하십시오.
언급URL : https://stackoverflow.com/questions/674027/what-should-a-json-service-return-on-failure-error
'codememo' 카테고리의 다른 글
| jsonb 필드의 PostgreSQL 이름 변경 특성 (0) | 2023.02.12 |
|---|---|
| Bad Image Format Exception 입니다.이 문제는 32비트 Oracle 클라이언트 컴포넌트가 설치된 상태에서 64비트 모드로 실행 중일 때 발생합니다. (0) | 2023.02.12 |
| Angularjs $state 새 탭의 링크 열기 (0) | 2023.02.12 |
| 플라스크 앱에서 다른 사이트로 GET 요청을 보내려면 어떻게 해야 하나요? (0) | 2023.02.12 |
| Springfox Swagger-UI가 추가되었지만 작동하지 않습니다. 제가 놓치고 있는 것은 무엇입니까? (0) | 2023.02.12 |