XML-RPC сервер с улучшенной отчетностью об ошибках

1

Стандартные библиотеки (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.

Теги:
xml-rpc

2 ответа

1
Лучший ответ

Похоже, что нет готовой библиотеки с моими требованиями, поэтому в итоге появилась собственная реализация:

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
1

Я не думаю, что у вас есть проблема с библиотекой. При использовании любой библиотеки или фреймворка вы, как правило, хотите уловить все ошибки, зарегистрировать их где-нибудь и выбросить "Упс, у нас проблемы. Вы можете связаться с нами по адресу [email protected] с номером ошибки 100 и сообщить нам, что ты сделал." Так что оберните свои отказоустойчивые точки входа в try/catch, создайте общий логгер и отпустите...

  • 1
    Затем они попытаются что-то описать, потерпят неудачу, и вы в конце концов включите ведение журнала (вероятно, огромных запросов), чтобы увидеть, что они на самом деле делают. Представьте себе сотни таких клиентов. Некоторые из них будут развиваться шаг за шагом, пройдя через все ошибки, которые вы можете себе представить, и даже больше.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню