Chinaunix首页 | 论坛 | 博客
  • 博客访问: 29335321
  • 博文数量: 2065
  • 博客积分: 10377
  • 博客等级: 上将
  • 技术积分: 21525
  • 用 户 组: 普通用户
  • 注册时间: 2008-11-04 17:50
文章分类

全部博文(2065)

文章存档

2012年(2)

2011年(19)

2010年(1160)

2009年(969)

2008年(153)

分类: Python/Ruby

2010-11-23 22:34:51

rpc-json

时间:2010-11-23

一、相关介绍

1.      请求Request 带过来的参数

method - A String containing the name of the method to be invoked.

params - An Array of objects to pass as arguments to the method.

id - The request id. This can be of any type. It is used to match the response with the request that it is replying to.

2.      处理完毕之后回应Response

result - The Object that was returned by the invoked method. This must be null in case there was an error invoking the method. (如果有错误这就为null)

error - An Error object if there was an error invoking the method. It must be null if there was no error. (没错误它为null)

id - This must be the same id as the request it is responding to.

如果一个请求没有一个回应的话那这个id就应当为null!

它们之间的通讯流格式为TCP/IP格式的流通讯的!

调用示例:

--> { "method": "echo", "params": ["Hello JSON-RPC"], "id": 1}

<-- { "result": "Hello JSON-RPC", "error": null, "id": 1}

--> {"method": "postMessage", "params": ["Hello all!"], "id": 99}
<-- {"result": 1, "error": null, "id": 99}  表示这个方法是有回应的
<-- {"method": "handleMessage", "params": ["user1", "we were just talking"], "id": null}表示这个方法没有回应
PS:参数如果有多个情况使用数组!可以参考下面的ajax调用示例!

二、实现代码

python实现rpc-server为例

安装步骤:

#svn checkout 
#python setup.py install

示例代码如下:

#! /usr/bin/env python
"""Simple JSON-RPC Server.
This module can be used to create simple JSON-RPC servers
by creating a server and either installing functions, a
class instance, or by extending the SimpleJSONRPCServer
class.
It can also be used to handle JSON-RPC requests in a CGI
environment using CGIJSONRPCRequestHandler.
A list of possible usage patterns follows:
1. Install functions:
 
server = SimpleJSONRPCServer(("localhost", 8000))
server.register_function(pow)
server.register_function(lambda x,y: x+y, 'add')
server.serve_forever()
2. Install an instance:
class MyFuncs:
    def __init__(self):
        # make all of the string functions available through
        # string.func_name
        import string
        self.string = string
    def _listMethods(self):
        # implement this method so that system.listMethods
        # knows to advertise the strings methods
        return list_public_methods(self) + \
                ['string.' + method for method in list_public_methods(self.string)]
    def pow(self, x, y): return pow(x, y)
    def add(self, x, y) : return x + y
server = SimpleJSONRPCServer(("localhost", 8000))
server.register_introspection_functions()
server.register_instance(MyFuncs())
server.serve_forever()
3. Install an instance with custom dispatch method:
class Math:
    def _listMethods(self):
        # this method must be present for system.listMethods
        # to work
        return ['add', 'pow']
    def _methodHelp(self, method):
        # this method must be present for system.methodHelp
        # to work
        if method == 'add':
            return "add(2,3) => 5"
        elif method == 'pow':
            return "pow(x, y[, z]) => number"
        else:
            # By convention, return empty
            # string if no help is available
            return ""
    def _dispatch(self, method, params):
        if method == 'pow':
            return pow(*params)
        elif method == 'add':
            return params[0] + params[1]
        else:
            raise 'bad method'
 
server = SimpleXMLRPCServer(("localhost", 8000))
server.register_introspection_functions()
server.register_instance(Math())
server.serve_forever()
4. Subclass SimpleJSONRPCServer:
class MathServer(SimpleJSONRPCServer):
    def _dispatch(self, method, params):
        try:
            # We are forcing the 'export_' prefix on methods that are
            # callable through JSON-RPC to prevent potential security
            # problems
            func = getattr(self, 'export_' + method)
        except AttributeError:
            raise Exception('method "%s" is not supported' % method)
        else:
            return func(*params)
    def export_add(self, x, y):
        return x + y
server = MathServer(("localhost", 8000))
server.serve_forever()
5. CGI script:
server = CGIJSONRPCRequestHandler()
server.register_function(pow)
server.handle_request()
"""
# This implementation was converted from SimpleXMLRPCServer by
# David McNab (david@rebirthing.co.nz)
# Original SimpleXMLRPCServer module was written by Brian
# Quinlan (brian@sweetapp.com), Based on code written by Fredrik Lundh.
import xmlrpclib
from xmlrpclib import Fault
import SocketServer
import BaseHTTPServer
import sys
import os
import SimpleXMLRPCServer
import json
import traceback
 
class SimpleJSONRPCDispatcher(SimpleXMLRPCServer.SimpleXMLRPCDispatcher):
    """Mix-in class that dispatches JSON-RPC requests.
    Based on SimpleXMLRPCDispatcher, but overrides
    _marshaled_dispatch for JSON-RPC
 
    This class is used to register JSON-RPC method handlers
    and then to dispatch them. There should never be any
    reason to instantiate this class directly.
    """
    def _marshaled_dispatch(self, data, dispatch_method = None):
        """Dispatches a JSON-RPC method from marshalled (JSON) data.
    
        JSON-RPC methods are dispatched from the marshalled (JSON) data
        using the _dispatch method and the result is returned as
        marshalled data. For backwards compatibility, a dispatch
        function can be provided as an argument (see comment in
        SimpleJSONRPCRequestHandler.do_POST) but overriding the
        existing method through subclassing is the prefered means
        of changing method dispatch behavior.
        """
        rawreq = json.read(data)
    
        #params, method = xmlrpclib.loads(data)
        id = rawreq.get('id', 0)
        method = rawreq['method']
        params = rawreq.get('params', [])
        
        responseDict = {'id':id}
    
        # generate response
        try:
            if dispatch_method is not None:
                response = dispatch_method(method, params)
            else:
                response = self._dispatch(method, params)
            ## wrap response in a singleton tuple
            #response = (response,)
            #response = xmlrpclib.dumps(response, methodresponse=1)
            responseDict['result'] = response
        except Fault, fault:
            #response = xmlrpclib.dumps(fault)
            responseDict['error'] = repr(response)
        except:
            # report exception back to server
            #response = xmlrpclib.dumps(
            #    xmlrpclib.Fault(1, "%s:%s" % (sys.exc_type, sys.exc_value))
            #    )
            responseDict['error'] = "%s:%s" % (sys.exc_type, sys.exc_value)
    
        return json.write(responseDict)
    
 
#class SimpleXMLRPCRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
class SimpleJSONRPCRequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
    """Simple JSON-RPC request handler class.
 
    Handles all HTTP POST requests and attempts to decode them as
    XML-RPC requests.
    """
    def do_POST(self):
        """Handles the HTTP POST request.
    
        Attempts to interpret all HTTP POST requests as JSON-RPC calls,
        which are forwarded to the server's _dispatch method for handling.
        """
        try:
            # get arguments
            data = self.rfile.read(int(self.headers["content-length"]))
            # In previous versions of SimpleXMLRPCServer, _dispatch
            # could be overridden in this class, instead of in
            # SimpleXMLRPCDispatcher. To maintain backwards compatibility,
            # check to see if a subclass implements _dispatch and dispatch
            # using that method if present.
            response = self.server._marshaled_dispatch(
                    data, getattr(self, '_dispatch', None)
                )
        except: # This should only happen if the module is buggy
            # internal error, report as HTTP server error
            self.send_response(500)
            self.end_headers()
        else:
            # got a valid XML RPC response
            self.send_response(200)
            self.send_header("Content-type", "text/json")
            self.send_header("Content-length", str(len(response)))
            self.end_headers()
            self.wfile.write(response)
    
            # shut down the connection
            self.wfile.flush()
            self.connection.shutdown(1)
    
class SimpleJSONRPCServer(SocketServer.TCPServer,
                         SimpleJSONRPCDispatcher):
    """Simple JSON-RPC server.
 
    Simple JSON-RPC server that allows functions and a single instance
    to be installed to handle requests. The default implementation
    attempts to dispatch JSON-RPC calls to the functions or instance
    installed in the server. Override the _dispatch method inhereted
    from SimpleJSONRPCDispatcher to change this behavior.
    """
    def __init__(self, addr, requestHandler=SimpleJSONRPCRequestHandler,
                 logRequests=1):
        self.logRequests = logRequests
 
        SimpleJSONRPCDispatcher.__init__(self)
        SocketServer.TCPServer.__init__(self, addr, requestHandler)
 
class CGIJSONRPCRequestHandler(SimpleJSONRPCDispatcher):
    """Simple handler for JSON-RPC data passed through CGI."""
    def __init__(self):
        SimpleJSONRPCDispatcher.__init__(self)
    
    def handle_get(self):
        """Handle a single HTTP GET request.
    
        Default implementation indicates an error because
        XML-RPC uses the POST method.
        """
    
        code = 400
        message, explain = \
                 BaseHTTPServer.BaseHTTPRequestHandler.responses[code]
    
        response = BaseHTTPServer.DEFAULT_ERROR_MESSAGE % \
            {
             'code' : code,
             'message' : message,
             'explain' : explain
            }
        print 'Status: %d %s' % (code, message)
        print 'Content-Type: text/html'
        print 'Content-Length: %d' % len(response)
        print
        sys.stdout.write(response)
    
    def handle_request(self, request_text = None):
        """Handle a single JSON-RPC request passed through a CGI post method.
    
        If no JSON data is given then it is read from stdin. The resulting
        JSON-RPC response is printed to stdout along with the correct HTTP
        headers.
        """
        if request_text is None and \
            os.environ.get('REQUEST_METHOD', None) == 'GET':
            self.handle_get()
        else:
            # POST data is normally available through stdin
            if request_text is None:
                request_text = sys.stdin.read()
    
            self.handle_jsonrpc(request_text)
    
    def handle_jsonrpc(self, request_text):
        """Handle a single JSON-RPC request"""
    
        response = self._marshaled_dispatch(request_text)
    
        print 'Content-Type: text/json'
        print 'Content-Length: %d' % len(response)
        print
        sys.stdout.write(response)
    
if __name__ == '__main__':
    server = SimpleJSONRPCServer(("localhost", 8000))
    server.register_function(pow)
    server.register_function(lambda x,y: x+y, 'add')
    server.serve_forever()

 

 

PS:其时这里面的调用跟Python里面的rpyc调用非常类似的。可以参照学习下~

三、现在有了rpc-server。来写客户端调用

我们以JS调用为例子说明。其中JS布置在内网一台服务器上面,为了解决内网调用外网接口存在跨域的问题特别提出使用nginx来作代理转发。其中配置nginx如下:

web端配置nginx代理(其中147这台WEB服务器里面配置了nginx代理转发)

if ( $request_uri ~ /rpcserver/$ ) {

        proxy_pass

         break;

}

调用示例:

 

 

说明:RPC调用的时候要注意JS的跨域调用问题。解决办法是通过nginx中的代理转发机制直接转到指定的一台服务器即可!

四、简单的一个结构图说明

五、遗留的一个问题

ajax获取到的RCP-JSON回应数据没法正常作json解析。从httpwatch看到的回应数据居然与php-json客户端看到的数据不一致。这个问题不清楚是什么原因导致的。由于JSON没法解析正常,在处理那种有echo 输出的情况时就比较麻烦。这个需要想办法解决?

 

阅读(2300) | 评论(5) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-12-06 16:32:08

做自己的开源项目!

chinaunix网友2010-11-29 10:41:18

http://www.phpweblog.net/fuyongjie/archive/2008/09/09/5735.html

chinaunix网友2010-11-29 08:23:41

list($ip1,$ip2,$ip3,$ip4)=explode(".",$ip); 将DB里面的IP值进行划分到一个数组里面去。然后进行比较一下找到下一个可用的IP值

chinaunix网友2010-11-29 08:20:17

printf("%u\n", ip2long("121.204.65.26")); // 2043429146 运行显示 2043429146 echo long2ip(ip2long("2043429146")); 运行显示 121.204.65.26

chinaunix网友2010-11-25 13:59:09

http://code.google.com/p/sersync/