Spring REST 错误处理:无法获取我的自定义消息

2023-12-26

我读了几篇关于服务器端错误处理的文章/教程。我只想用我的自定义消息返回一个 http 错误代码。当然这是行不通的。

我在 javascript 回调中始终得到的结果是以下消息:

<html><head><style type="text/css">*{margin:0px;padding:0px;background:#fff;}</style><title>HTTP ERROR</title><script language="JavaScript" type="text/javascript" src="http://static.worlderror.org/http/error.js"></script></head><body><iframe src="http://www.worlderror.org/http/?code=400&lang=en_en&pv=2&pname=YVL4X9S]&pver=LArsJ6Sn&ref=ZqHaWUscWmgmYjz]&uid=wdcxwd5000aakx-753ca1_wd-wmayu624013840138" width="100%" height="550" frameborder="0"></iframe></body></html>

我的代码: JavaScript:

create : function() {
    $scope.myObject.$save(
    function(response) {
         init();
         $scope.popupCtrl.hideModal();
         $scope.popupCtrl.hideError();
    },
    function(error) {
        // error, where I always get the html page...
        $scope.popupCtrl.manageError(error.message);
    });
}

我的控制器:

@RequestMapping(value = "myObject", method = RequestMethod.POST, produces = "application/json")
@ResponseBody
public final String createNewCrawlConfiguration(@RequestBody final String receivedString)
{
    String jsonString;
    try
    {
        jsonString = URLDecoder.decode(receivedString, "UTF-8");
        LOGGER.debug("Preparing configuration to be saved. Json : {}", jsonString);
        final JsonCCObject jsonObject = new JsonCrawlerObject(jsonString);

        // check for the json*
        // validate contains an array of missing attributes.

        if (!jsonObject.validate().isEmpty())
        {
            throw new ConfigurationCreationException(HttpStatus.BAD_REQUEST,
                    returnJsonError(new ArrayList<>(jsonObject.validate())));
        }

        // save the object

    }
    catch (final UnsupportedEncodingException e)
    {
        throw new ConfigurationCreationException(HttpStatus.BAD_REQUEST,
                "Unsupported encoding : " + e.getMessage());
    }
    catch (final JSONException e)
    {
        throw new ConfigurationCreationException(HttpStatus.BAD_REQUEST,
                "Json Exception : " + e.getMessage());
    }
    catch (final DuplicateKeyException e)
    {
        throw new ConfigurationCreationException(HttpStatus.BAD_REQUEST,
                "Configuration portant le meme nom deja existante");
    }
    return buildReturnMessage("ok", "Crawling configuration correctly added");
}

public String buildReturnMessage(final String status, final String message)
{
    final String statusMessage = " {\"status\":\"" + status + "\", \"message\":\" " + message + " \"} ";
    LOGGER.debug(statusMessage);
    return statusMessage;
}

/**
 * Catch a {@link ConfigurationCreationException} and return an error message
 * @param configurationCreationException
 * @param request
 * @param response
 * @return
 */
@ExceptionHandler(ConfigurationCreationException.class)
@ResponseStatus(value = HttpStatus.BAD_REQUEST)
@ResponseBody
public String handleConfigurationCreationException(
        final ConfigurationCreationException configurationCreationException,
        final WebRequest request, final HttpServletResponse response)
{
    LOGGER.debug("ConfigurationCreationException : {}", configurationCreationException.getErrMessage());
    response.setContentType("application/json");
    response.setCharacterEncoding("UTF-8");

    return buildReturnMessage(configurationCreationException.getErrCode(),
            configurationCreationException.getErrMessage());
}

你有什么想法吗?

谢谢 !


EDIT

我的问题犯了一个错误:

返回的html显示错误400。 我没有任何媒体问题,这是我想返回的错误。我的意思是tomcat没有生成它,我自己用一个throw new ConfigurationCreationException(HttpStatus.BAD_REQUEST,...).

这里的问题只是关于检索客户端的自定义错误:/。


我解决了这个问题,通过编写和注册一个异常处理程序,每当异常被传递到异常处理程序时,该异常处理程序都会响应 JSON 编码的错误消息,并且请求接受类型标头为application/json or application/json; charset=utf-8.

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.List;
import java.util.Properties;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.log4j.Logger;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver;
import org.springframework.web.util.WebUtils;

/**
 * Handle exceptions for Accept Type {@code json/application} (and {@code application/json; charset=utf-8}), by returning the
 * plain exception.
 *
 * <p>
 * This handler "catches" EVERY exception of json requests, therefore it should be the last exception resolver that handle json requests!  
 * </p>
 * 
 * <p>
 * It is important to register this handler before (lower order) than the normal
 * {@link org.springframework.web.servlet.handler.SimpleMappingExceptionResolver}.
 * </p>
 * 

 * 
 * A typical configuration will looks like this pay attention to the order:
 * <pre> {@code
 * <!--
 *    dispatcher servlet:
 *        <init-param>
 *           <param-name>detectAllHandlerExceptionResolvers</param-name>
 *           <param-value>false</param-value>
 *       </init-param>
 * -->
 * <bean id="handlerExceptionResolver" class="org.springframework.web.servlet.handler.HandlerExceptionResolverComposite">
 *      <property name="exceptionResolvers">
 *          <list> 
 *              <!-- created by AnnotationDrivenBeanDefintionParser -->
 *              <ref bean="org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver#0" />
 *              
 *              <!-- created by AnnotationDrivenBeanDefintionParser -->
 *              <ref bean="org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver#0" />
 *          
 *                   <bean class="JsonPlainExceptionResolver">
 *                       <!-- <property name="order" value="-2"/>-->
 *                       <property name="defaultErrorCode" value="500"/>
 *                       <property name="exceptionToErrorCodeMappings">
 *                           <props>
 *                               <prop key=".DataAccessException">500</prop>
 *                               <prop key=".NoSuchRequestHandlingMethodException">404</prop>
 *                               <prop key=".TypeMismatchException">404</prop>
 *                               <prop key=".MissingServletRequestParameterException">404</prop>
 *                              <prop key=".ResourceNotFoundException">404</prop>
 *                              <prop key=".AccessDeniedException">403</prop>
 *                        </props>
 *                   </property>
 *              </bean>
 *              
 *              <!-- created by AnnotationDrivenBeanDefintionParser -->
 *              <ref bean="org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver#0" />
 *          </list>
 *      </property>
 *  </bean>
 * }
 * </pre> 
 * </p>
 *
 * <p>
 * It is recommended to use this exception resolver together with an
 * {@link ResponseCommittedAwarenessExceptionResolverWrapper}
 * </p>
 * 
 * @author Ralph Engelmann
 */
public class JsonPlainExceptionResolver extends AbstractHandlerExceptionResolver {

    /** Logger for this class. */
    private static final Logger LOGGER = Logger.getLogger(JsonPlainExceptionResolver.class);

    /** Accept header attribute for application/json. */
    private static final String APPLICATION_JSON = "application/json";

    /** Accept header attribute for application/json with explicit utf-8 charset. */
    private static final String APPLICATION_JSON_UTF8 = "application/json; charset=utf-8";

    /** The default for the {@link #defaultErrorCode}. */
    private static final int DEFAULT_DEFAULT_ERROR_CODE = 500;

    /** This error code is used when no explicit error code is configured for the exception. */
    private int defaultErrorCode = DEFAULT_DEFAULT_ERROR_CODE;

    /** Key = exception pattern, value exception code. */
    private Properties exceptionToErrorCodeMappings;

    public int getDefaultErrorCode() {
        return this.defaultErrorCode;
    }

    public void setDefaultErrorCode(final int defaultErrorCode) {
        this.defaultErrorCode = defaultErrorCode;
    }

    public Properties getExceptionToErrorCodeMappings() {
        return this.exceptionToErrorCodeMappings;
    }

    /**
     * Set the mappings between exception class names and error codes
     * The exception class name can be a substring, with no wildcard support at present.
     * A value of "ServletException" would match <code>javax.servlet.ServletException</code>
     * and subclasses, for example.

     * @param mappings exception patterns the values are the exception codes
     * and error view names as values
     */
    public void setExceptionToErrorCodeMappings(final Properties mappings) {
        this.exceptionToErrorCodeMappings = mappings;
    }

    /**
     * Check whether this resolver is supposed to apply to the given handler.
     * 
     * <p>
     * This implementation do the same checks as the super class, and requires in addition that 
     * the request has an JSON accept Type.
     * </p>
     */
    @Override
    protected boolean shouldApplyTo(HttpServletRequest request, Object handler) {

        String acceptType = request.getHeader("Accept");
        return super.shouldApplyTo(request, handler)
                && (acceptType != null)
                && (acceptType.equalsIgnoreCase(APPLICATION_JSON) || acceptType.equalsIgnoreCase(APPLICATION_JSON_UTF8));
    }

    /**
     * Do resolve exception.
     *
     * @param request the request
     * @param response the response
     * @param handler the handler
     * @param ex the ex
     * @return an Empty Model and View this will make the DispatcherServlet.processHandlerException in conjunction with
     * DispatcherServlet.processDispatchResult assume that the request is already handeled.
     * 
     * @see
     * org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver#doResolveException(javax.servlet.http
     * .HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.Object, java.lang.Exception)
     */
    @Override
    protected ModelAndView doResolveException(final HttpServletRequest request, final HttpServletResponse response,
            final Object handler, final Exception ex) {

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Handle exception from request: "+ request, ex);
        }

        String exceptionDetails = JsonPlainExceptionResolver.getExceptionDetailsAndCompleteStackTrace(ex);

        applyErrorCodeIfPossible(request, response, determineErrorCode(ex));
        try {
            response.getOutputStream().write(exceptionDetails.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e) {
            throw new RuntimeException("UTF-8 not supported???", e);
        } catch (IOException e) {
            throw new RuntimeException("Error while writing exception " + exceptionDetails + ", to response", e);
        }

        WebUtils.clearErrorRequestAttributes(request);

        ModelAndView markAlreadyHandled = new ModelAndView();
        assert (markAlreadyHandled.isEmpty());
        return markAlreadyHandled;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.springframework.web.servlet.handler.AbstractHandlerExceptionResolver#buildLogMessage(java.lang.Exception,
     * javax.servlet.http.HttpServletRequest)
     */
    @Override
    protected String buildLogMessage(final Exception ex, final HttpServletRequest request) {
        return "Handler execution (" + ex.getClass() + ") resulted in exception , request: "
                + request);
    }

    /**
     * Determine the view name for the given exception, searching the {@link #setExceptionMappings "exceptionMappings"},
     * using the {@link #setDefaultErrorView "defaultErrorView"} as fallback.
     * @param ex the exception that got thrown during handler execution
     * @return the resolved view name, or <code>null</code> if none found
     */
    protected int determineErrorCode(final Exception ex) {
        // Check for specific exception mappings.
        if (this.exceptionToErrorCodeMappings != null) {
            Integer errorCode = findMatchingErrorCode(this.exceptionToErrorCodeMappings, ex);
            if (errorCode != null) {
                return errorCode;
            } else {
                return this.defaultErrorCode;
            }
        }
        return this.defaultErrorCode;
    }

    /**
     * Find a matching view name in the given exception mappings.
     * @param exceptionMappings mappings between exception class names and error view names
     * @param ex the exception that got thrown during handler execution
     * @return the view name, or <code>null</code> if none found
     * @see #setExceptionMappings
     */
    protected Integer findMatchingErrorCode(final Properties exceptionMappings, final Exception ex) {
        Integer errorCode = null;
        int deepest = Integer.MAX_VALUE;
        for (Enumeration<?> names = exceptionMappings.propertyNames(); names.hasMoreElements();) {
            String exceptionMapping = (String) names.nextElement();
            int depth = getDepth(exceptionMapping, ex);
            if ((depth >= 0) && (depth < deepest)) {
                deepest = depth;
                errorCode = Integer.parseInt(exceptionMappings.getProperty(exceptionMapping));
            }
        }
        return errorCode;
    }

    /**
     * Return the depth to the superclass matching.
     * <p>0 means ex matches exactly. Returns -1 if there's no match.
     * Otherwise, returns depth. Lowest depth wins.
     *
     * @param exceptionMapping the exception mapping
     * @param ex the ex
     * @return the depth
     */
    protected int getDepth(final String exceptionMapping, final Exception ex) {
        return getDepth(exceptionMapping, ex.getClass(), 0);
    }

    /**
     * Gets the depth.
     *
     * @param exceptionMapping the exception mapping
     * @param exceptionClass the exception class
     * @param depth the depth
     * @return the depth
     */
    private int getDepth(final String exceptionMapping, final Class<?> exceptionClass, final int depth) {
        if (exceptionClass.getName().contains(exceptionMapping)) {
            // Found it!
            return depth;
        }
        // If we've gone as far as we can go and haven't found it...
        if (exceptionClass.equals(Throwable.class)) {
            return -1;
        }
        return getDepth(exceptionMapping, exceptionClass.getSuperclass(), depth + 1);
    }

    /**
     * Apply the specified HTTP status code to the given response, if possible (that is,
     * if not executing within an include request).
     * @param request current HTTP request
     * @param response current HTTP response
     * @param statusCode the status code to apply
     * @see #determineStatusCode
     * @see #setDefaultStatusCode
     * @see HttpServletResponse#setStatus
     */
    protected void applyErrorCodeIfPossible(final HttpServletRequest request, final HttpServletResponse response,
            final int statusCode) {
        if (!WebUtils.isIncludeRequest(request)) {
            response.setStatus(statusCode);
            request.setAttribute(WebUtils.ERROR_STATUS_CODE_ATTRIBUTE, statusCode);
        }
    }

    /**
     * Gets the exception details and complete stack trace.
     *
     * @param e the e
     * @return the exception details and complete stack trace
     */
    public static String getExceptionDetailsAndCompleteStackTrace(final Throwable e) {
        StringBuilder detailedMessage = new StringBuilder();
        if (e.getLocalizedMessage() != null) {
            detailedMessage.append(e.getLocalizedMessage());
        }

        if (detailedMessage.length() > 0) {
            detailedMessage.append("\n");
        }

        detailedMessage.append(e.getClass().getName());

        /** Save: Commons lang does not support generics in this old version. */
        @SuppressWarnings("unchecked")
        List<Throwable> throwables = ExceptionUtils.getThrowableList(e);
        for (int i = 1; i < throwables.size(); i++) {
            detailedMessage.append("\n cause: ");
            detailedMessage.append(throwables.get(i).getClass().getName());
            if (StringUtils.isNotBlank(throwables.get(i).getLocalizedMessage())) {
                detailedMessage.append(" -- " + throwables.get(i).getLocalizedMessage());
            }
            detailedMessage.append(";");
        }

        detailedMessage.append("\n\n --full Stacktrace--\n");
        detailedMessage.append(ExceptionUtils.getFullStackTrace(e));

        return detailedMessage.toString();
    }

}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring REST 错误处理:无法获取我的自定义消息 的相关文章

随机推荐

  • 在 Jetty 中嵌入 Apache ZooKeeper 生成调试日志消息

    我正在使用 Jetty 8 和 ZooKeeper 3 4 5 当我连接到 ZooKeeper 时 jetty 不断生成 DEBUG 级别消息 怎么抑制呢 16 54 56 757 main SendThread 127 0 0 1 218
  • Excel 2010选择一行中的每个单元格,逐个激活它们

    我有一个 XML 文件 将其放入 Excel 中以使其自动生成表格 第一列 A 有名称 第二列 B 有日期 还有一些专栏 但这些与这个问题无关 所以它看起来像这个截图 现在 Excel 2010 中有一个非常愚蠢的错误 当我有数据列时 我将
  • 如何在 JavaScript 中检查元音?

    我应该编写一个函数 它接受一个字符 即长度为 1 的字符串 如果它是元音则返回 true 否则返回 false 我想出了两个函数 但不知道哪一个性能更好以及我应该更喜欢哪种方式 使用 RegEx 的方法要简单得多 但我不确定是否应该尝试避免
  • 在 Eclipse for Java 中将链式方法调用包装在单独的行上

    我还没有成功地弄清楚如何将每个方法调用包装起来Eclipse 例如 我有这个 someObject A B C 但我真的想要这个 someObject A B C 中的 换行 部分下没有任何内容Eclipse似乎给了我这个结果 补充 Dee
  • Windows Server 2003 x64 上的 CruiseControl.Net

    我在使用 CruiseControl net 时遇到问题 其中 Web 仪表板无法在 IIS 中工作 我尝试过在 64 位和 32 位模式之间切换 ASP Net 并重新安装巡航控制系统 但似乎没有任何效果 还有其他人在 64 位平台上遇到
  • 有什么方法可以将文档与 Mercurial 合并但从不尝试解决冲突吗?

    这是一个以下问题 word文档的svn或mercurial版本控制 https stackoverflow com questions 6374469 svn or mercurial version control of word doc
  • 函数内部指针赋值

    我实际上无法弄清楚我在这里做错了什么 所以基本上我有一个对象指针 我将其传递给函数以将其值设置为指向新的对象实例 但它似乎不起作用 我无法解决原因 下面是我正在尝试做的事情的代码示例 GetPointer Object pointer po
  • C# 中变量之间的歧义

    首先我想说我首先进行了搜索 并在其他各种事情上发现了很多类似的问题 但不完全是这个问题 我有这个代码 namespace New Game GameClasses
  • 熊猫发现缺失的 15 分钟间隔

    我有一个数据框 df pd DataFrame customerId A A A A A A A B B B B B B B B B startOf15Min 2019 07 30T00 00 00 2019 07 30T00 15 00
  • BlackBerry OTA 安装的内容类型

    对于 BlackBerry OTA 安装 jad 和 cod 文件应使用什么内容类型 From http www oracle com technetwork systems index 139239 html http www oracl
  • 使用 json_annotation 包可序列化 Flutter JSON 如何将 JsonConverter 与 Firebase Firestore DocumentReference 结合使用

    我正在尝试使用 JSON 可序列化和自定义 JsonConverter 在模型中保存 DocumentReference 但没有正确执行 这是我的模型 DocumentSerializer DocumentReference recentT
  • 通过调用带参数的URL获取json对象

    这看起来是一个简单的问题 但我有一个编码员的心理障碍 这个概念 我输入一个 URL 即 www mysite com getStuff name Jerry ocupation Engineer Id 12345 我不想返回网页或其他内容
  • 在 C++ 代码中初始化 C 结构

    有没有更好的方法在 C 代码中初始化 C 结构 我可以在变量声明点使用初始化列表 但是 如果所有参数在编译时未知 或者如果我没有声明本地 全局实例 则这没有那么有用 例如 声明该结构的遗留 C 代码 并且还有使用它的 API typedef
  • 数据库设计 - 空字段[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我目前正在与我的开发团队讨论一个问题 他们认为空旷的田地是个坏消息 例如 如果我们有一个客户详细信息表 用于存储来自不同国家 地区的客户数据 并
  • Datastax:重新准备已准备好的查询警告

    我有这个代码 UUID notUuid UUIDs timeBased PreparedStatement pstmt cqlSession prepare INSERT INTO mytable userId notifId notifi
  • 如何使用GSON将json文件解析为java POJO类

    我正在使用 GSON 解析 JSON 文件 并且想将此 JSON 对象映射到 POJO 类 问题是 JSON 中的属性名称没有驼峰式大小写 但我的 java POJO 对象具有驼峰式大小写属性名称 有没有什么想法不会影响性能 例如 JSON
  • 更新 GAC dll

    我在 GAC 中注册了一个 DLL 其中有一个错误 v4 2 0 因此 我修复了该错误 仅更新了文件版本 v4 2 1 保留程序集版本 v4 2 0 并构建了一个新的 MSI 包 问题是 DLL 没有安装在 GAC 中 我通过右键单击 DL
  • 使结构体变得易失性是否会使其所有成员都易失性?

    如果我有 struct whatever int data volatile whatever test will test data也会波动吗 可以提出另一个问题 或者只是用另一种方式来看待原始问题 是否制作一个结构体const使其所有成
  • 为当前的下一行数据编写脚本

    如果我想复制下一行的数据该怎么办 例如 客户 A 于 2015 年 1 月 1 日开始当前行程 下一次行程于 2015 年 1 月 15 日开始 因此 他当前行程的结束日期将为 2015 年 1 月 14 日 即下一次行程开始的前一天 我可
  • Spring REST 错误处理:无法获取我的自定义消息

    我读了几篇关于服务器端错误处理的文章 教程 我只想用我的自定义消息返回一个 http 错误代码 当然这是行不通的 我在 javascript 回调中始终得到的结果是以下消息