代码之家  ›  专栏  ›  技术社区  ›  Denis Otkidach

具有更好错误报告功能的XML-RPC服务器

  •  1
  • Denis Otkidach  · 技术社区  · 16 年前

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

    XMLRPCLIB 已经有了这些错误的常量: NOT_WELLFORMED_ERROR , UNSUPPORTED_ENCODING , INVALID_ENCODING_CHAR , INVALID_XMLRPC , METHOD_NOT_FOUND , INVALID_METHOD_PARAMS , INTERNAL_ERROR .

    2 回复  |  直到 16 年前
        1
  •  1
  •   popester    16 年前

    我认为你没有图书馆特有的问题。当使用任何库或框架时,您通常希望捕获所有错误,将它们记录到某个地方,然后抛出“oops,我们遇到了问题”。您可能想通过x@x.com与我们联系,并告诉我们您做了什么。“因此,将您的可失败入口点包装在try/catch中,创建一个通用的记录器,然后离开……

        2
  •  1
  •   Denis Otkidach    16 年前

    看起来没有现成的库满足我的需求,因此a最终实现了自己的实现:

    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
    
    推荐文章