[From HTTP to AWS][3] Web Services: XMLRPC/SOAP/RESTful
XMLRPC – SOAP RPC – RESTful RPC
本文将以代码、Request和Response三个不同的视角来分析三种不同的RPC方式。
· XMLRPC/JSONRPC(宝莱坞)
这是Leonard Richardson之《Restful Web Services》一书中的例子。
An example in Ruby:
#!/usr/bin/ruby -w # xmlrpc-upc.rb require 'xmlrpc/client' def find_product(upc) server = XMLRPC::Client.new2('http://www.upcdatabase.com/rpc') begin response = server.call('lookupUPC', upc) rescue XMLRPC::FaultException => e puts "Error: " puts e.faultCode puts e.faultString end end puts find_product("001441000055")['description'] # "Trader Joe's Thai Rice Noodles" |
Rewrite in Python:
#!/usr/bin/python import xmlrpclib def find_product(upc): server = xmlrpclib.ServerProxy('http://www.upcdatabase.com/rpc') result = server.lookupUPC(upc) if type(result) == dict: if result['found']: return result['description'] else: return result['message'] return "" print find_product("001441000055") # Trader Joe's Thai Rice Noodles |
Request:
<?xml version="1.0" ?> <methodCall> <methodName>lookupUPC</methodName> <params> <param><value><string>001441000055</string></value></param> </params> </methodCall> |
Response:
HTTP/1.1 200 OK Date: Mon, 16 Aug 2010 13:49:58 GMT Server: Apache Vary: Accept-Encoding Connection: close Content-Type: text/xml <?xml version="1.0"?> <methodResponse> <params> <param><value><struct> <member><name>upc</name><value><string>001441000055</string></value> </member> <member><name>pendingUpdates</name><value><int>0</int></value> </member> <member><name>isCoupon</name><value><boolean>0</boolean></value> </member> <member><name>ean</name><value><string>0001441000055</string></value> </member> <member><name>issuerCountryCode</name><value><string>us</string></value> </member> <member><name>found</name><value><boolean>1</boolean></value> </member> <member><name>description</name><value><string>Trader Joe's Thai Rice Noodles</string></value> </member> <member><name>size</name><value><string>12 oz.</string></value> </member> <member><name>message</name><value><string>Database entry found</string></value> </member> <member><name>issuerCountry</name><value><string>United States</string></value> </member> <member><name>lastModified</name><value><string>2006-10-01 18:11:27</string></value> </member> <member><name>upce</name><value><string>00144155</string></value> </member> </struct></value> </param> </params> </methodResponse> |
· SOAP RPC(好莱坞)
In actual, SOAP is not just about HTTP. It’s also about SMTP and some other protocols.
The reason why it’s based on HTTP is just for pass through firewall.
下面这个例子调用ChinaStock的SOAP API,获得沪深股市某只股票的行情。其实好多基金网站和股票行情网站都是这样干的。
// 61.147.124.120 // class SoapQuery { public static string GetSource() { return "http://www.webxml.com.cn/WebServices/ChinaStockWebService.asmx"; } // getStockInfo // public static string GetStockInfo(string code) { ChinaStockWebService.cn.com.webxml.www.ChinaStockWebService oService = new ChinaStockWebService.cn.com.webxml.www.ChinaStockWebService(); string[] info_byte = oService.getStockInfoByCode(code); string strInfo = ""; foreach (string strLine in info_byte) { strInfo = strInfo + "\n" + strLine; } return strInfo; } // Save Stock Image to local file // public static void GetStockImage(string code, string filename) { ChinaStockWebService.cn.com.webxml.www.ChinaStockWebService oService = new ChinaStockWebService.cn.com.webxml.www.ChinaStockWebService(); byte[] image_bytes = oService.getStockImageByteByCode(code); Image image = CovertUtil.byteArrayToImage(image_bytes); image.Save(filename); } }; |
运行结果
Request
// Request from CommView HTTP Analyzer POST /WebServices/ChinaStockWebService.asmx HTTP/1.1 User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 2.0.50727.3603) VsDebuggerCausalityData: uIDPowOEuUJZbqRJtxAFcA/WSHkAAAAA1gzbkv7ONEGsZ5se4/oaBJ00bq++H01LmgVGJKWdaA4ACQAA Content-Type: text/xml; charset=utf-8 SOAPAction: "http://WebXml.com.cn/getStockInfoByCode" Host: www.webxml.com.cn Content-Length: 354 Expect: 100-continue Connection: Keep-Alive HTTP/1.1 100 Continue xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><getStockInfoByCode xmlns="http://WebXml.com.cn/"><theStockCode>sh000001</theStockCode></getStockInfoByCode></soap:Body></soap:Envelope> |
Response
// Response from CommView HTTP Analyzer HTTP/1.1 200 OK Date: Mon, 16 Aug 2010 07:44:34 GMT Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-AspNet-Version: 2.0.50727 Cache-Control: private, max-age=0 Content-Type: text/xml; charset=utf-8 Content-Length: 832 <?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><getStockInfoByCodeResponse xmlns="http://WebXml.com.cn/"><getStockInfoByCodeResult><string>sh000001</string><string>上è¯æŒ‡æ•°</string><string>2010-08-16 15:03:09</string><string>2661.708</string><string>2606.700</string><string>2603.792</string><string>55.01</string><string>2596.771</string><string>2665.314</string><string>2.11%</string><string>1258628.23</string><string>13073685.1353</string><string /><string /><string /><string /><string /><string /><string /><string /><string /><string /><string /><string /><string /></getStockInfoByCodeResult></getStockInfoByCodeResponse></soap:Body></soap:Envelope> |
· RESTful RPC(原生态)
{code} // 60.28.0.266 // class RESTfulQuery { public static string GetSource() { return "http://hq.sinajs.cn"; } public static string GetStockInfo(string code) { string uri = "http://hq.sinajs.cn/list=" + code; HttpWebRequest request = CreateWebRequest(uri); //request.TransferEncoding = "GBK"; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); StreamReader responsestream = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("GBK")); return responsestream.ReadToEnd(); } // Save Stock Image to local file public static void GetStockImage(string code, string filename) { string uri = "http://image.sinajs.cn/newchart/daily/n/" + code + ".gif"; try { HttpWebRequest request = CreateWebRequest(uri); HttpWebResponse response = (HttpWebResponse)request.GetResponse(); Image image = Image.FromStream(response.GetResponseStream()); image.Save(filename); } catch (Exception e) { MessageBox.Show("Failed to query Stock infromation"); filename = ""; } } public static HttpWebRequest CreateWebRequest(string uri) { return (HttpWebRequest)WebRequest.Create(uri); } }; |
运行结果
Request
// Request from Commview HTTP Analyzer GET /list=sh000001 HTTP/1.1 Host: hq.sinajs.cn |
Response
//Response from CommView HTTP Analyzer HTTP/1.1 200 OK Cache-Control: no-cache Content-Length: 164 Connection: Keep-Alive Content-Type: application/x-javascript; charset=GBK var hq_str_sh000001="ÉÏÖ¤Ö¸Êý,2603.792,2606.700,2661.708,2665.314,2596.771,0,0,125862823,130736851353,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2010-08-16,15:03:09"; |
RESTful方式的架构意味着方法信息体现在HTTP方法里;
XMLRPC and SOAP, all requests are based on POST method.
An interesting example of AWS is that Amazon called non-SOAP API as Query API, not RESTful API.
在Leonard的书中提到了ROA;它则表明作用域信息存在于URI内;
对于一个基于ROA的RESTful Web Service,我们应该从URI就能基本了解客户端的请求,而HTTP Request部分,则定义了方法的具体信息。
可能的Representation Format: XML, JSON, ATOM Publish, XHTML..