【问题标题】:XML-RPC server with better error reporting具有更好错误报告的 XML-RPC 服务器
【发布时间】:2009-10-15 10:50:52
【问题描述】:

标准库(Python 2 中的xmlrpclib+SimpleXMLRPCServer 和Python 3 中的xmlrpc.server)将所有错误(包括使用错误)报告为不适合公共服务的python 异常:异常字符串通常不易理解没有python知识,可能会暴露一些敏感信息。解决这个问题并不难,但我更愿意避免重新发明轮子。有没有更好的错误报告的第三方库?我对所有使用错误的良好故障消息感兴趣,并在报告内部错误时隐藏内部信息(最好使用日志记录)。

xmlrpclib 已经有此类错误的常量:NOT_WELLFORMED_ERRORUNSUPPORTED_ENCODINGINVALID_ENCODING_CHARINVALID_XMLRPCMETHOD_NOT_FOUNDINVALID_METHOD_PARAMSINTERNAL_ERROR

【问题讨论】:

    标签: python xml-rpc


    【解决方案1】:

    我认为您没有特定于库的问题。使用任何库或框架时,您通常希望捕获所有错误,将它们记录在某处,然后抛出“糟糕,我们遇到了问题。您可能需要通过 x@x.com 与我们联系,错误号为 100,并告诉我们发生了什么你做到了。”因此,将您的失败入口点包装在 try/catch 中,创建一个通用记录器,然后就可以开始了......

    【讨论】:

    • 然后他们会尝试描述一些东西,失败了,你最终以启用日志记录(可能是巨大的请求)结束,看看他们实际做了什么。想象一下数百个这样的客户。他们中的一些人会一步一步地发展,克服你能想象到的所有错误,甚至更多。
    【解决方案2】:

    看起来我的要求没有现成的库,所以最终有自己的实现:

    class ApplicationError(Fault):
    
        def __init__(self, exc_info):
            Fault.__init__(self, xmlrpclib.APPLICATION_ERROR,
                           u'Application internal error')
    
    
    class NotWellformedError(Fault):
    
        def __init__(self, exc):
            Fault.__init__(self, xmlrpclib.NOT_WELLFORMED_ERROR, str(exc))
    
    
    class UnsupportedEncoding(Fault):
    
        def __init__(self, exc):
            Fault.__init__(self, xmlrpclib.UNSUPPORTED_ENCODING, str(exc))
    
    
    # XXX INVALID_ENCODING_CHAR is masked by xmlrpclib, so the error code will be
    # INVALID_XMLRPC.
    class InvalidRequest(Fault):
    
        def __init__(self, message):
            ault.__init__(self, xmlrpclib.INVALID_XMLRPC, message)
    
    
    class MethodNotFound(Fault):
    
        def __init__(self, name):
            Fault.__init__(self, xmlrpclib.METHOD_NOT_FOUND,
                           u'Method %r is not supported' % name)
    
    
    class WrongMethodUsage(Fault):
    
        def __init__(self, message):
            Fault.__init__(self, xmlrpclib.INVALID_METHOD_PARAMS, message)
    
    
    class WrongType(Fault):
    
        def __init__(self, arg_name, type_name):
            Fault.__init__(self, xmlrpclib.INVALID_METHOD_PARAMS,
                           u'Parameter %s must be %s' % (arg_name, type_name))
    
    
    class XMLRPCDispatcher(SimpleXMLRPCDispatcher, XMLRPCDocGenerator):
    
        server_name = server_title = 'Personalization center RPC interface'
        server_documentation = 'Available methods'
    
        def __init__(self, methods):
            SimpleXMLRPCDispatcher.__init__(self, allow_none=True, encoding=None)
            self.register_instance(methods)
            self.register_multicall_functions()
            #self.register_introspection_functions()
    
        def _dispatch(self, method_name, args):
            if self.funcs.has_key(method_name):
                method = self.funcs[method_name]
            else:
                method = self.instance._getMethod(method_name)
            arg_names, args_name, kwargs_name, defaults = \
                                                    inspect.getargspec(method)
            assert arg_names[0]=='self'
            arg_names = arg_names[1:]
            n_args = len(args)
            if not (args_name or defaults):
                if n_args!=len(arg_names):
                    raise WrongMethodUsage(
                        u'Method %s takes exactly %d parameters (%d given)' % \
                                    (method_name, len(arg_names), n_args))
            else:
                min_args = len(arg_names)-len(defaults)
                if len(args)<min_args:
                    raise WrongMethodUsage(
                        u'Method %s requires at least %d parameters (%d given)' % \
                                    (method_name, min_args, n_args))
                if not args_name and n_args>len(arg_names):
                    raise WrongMethodUsage(
                        u'Method %s requires at most %d parameters (%d given)' % \
                                    (method_name, len(arg_names), n_args))
            try:
                return method(*args)
            except Fault:
                raise
            except:
                logger.exception('Application internal error for %s%r',
                                 method_name, args)
                raise ApplicationError(sys.exc_info())
    
        def dispatch(self, data):
            try:
                try:
                    args, method_name = xmlrpclib.loads(data)
                except ExpatError, exc:
                    raise NotWellformedError(exc)
                except LookupError, exc:
                    raise UnsupportedEncoding(exc)
                except xmlrpclib.ResponseError:
                    raise InvalidRequest('Request structure is invalid')
                method_name = method_name.encode('ascii', 'replace')
                result = self._dispatch(method_name, args)
            except Fault, exc:
                logger.warning('Fault %s: %s', exc.faultCode, exc.faultString)
                return xmlrpclib.dumps(exc)
            else:
                try:
                    return xmlrpclib.dumps((result,), methodresponse=1)
                except:
                    logger.exception('Application internal error when marshalling'\
                                     ' result for %s%r', method_name, args)
                    return xmlrpclib.dumps(ApplicationError(sys.exc_info()))
    
    
    class InterfaceMethods:
    
        def _getMethod(self, name):
            if name.startswith('_'):
                raise MethodNotFound(name)
            try:
                method = getattr(self, name)
            except AttributeError:
                raise MethodNotFound(name)
            if not inspect.ismethod(method):
                raise MethodNotFound(name)
            return method
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-07
      相关资源
      最近更新 更多