常见的四种API:SOAP vs RPC vs REST vs GraphQL

杂谈

最近数据安全非常的火,由此衍生的API安全成为了很多人的焦点,由此,我们最近会通过视频讲解、图文讲解的形式带大家来了解API。

视频讲解

本期视频我们将从API的发展史,给大家梳理SOAP、RPC、REST、GraphQL常见的这四种API通讯方式,它们各有哪些优势?后出的就一定比之前的要好吗?

API发展史

图片[1]-常见的四种API:SOAP vs RPC vs REST vs GraphQL-FancyPig's blog
一张图看懂API发展历程

主流API技术

Request-Response Api

  • RPC(Remote Procedure Call)
  • Soap(Simple Object Acess Protocols)
  • REST(Representational State Transfer)
  • GraphQL

EDA(Event-Driven Architecture) Api

  • Webhook

API对比

对比RPCSoapRESTGraphQL
发行时间1998年XML-RPC
2005年JSON-RPC
2016年gRPC
1999年2000年2015年
支持格式JSON,XML,Protobuf,
Thrift,Flatbuffers
仅支持XMLXML,JSON,HTML,
纯文本
JSON
上手难度简单困难简单中等
社区成长中
应用场景支付网关
身份管理
客户关系管理解决方案
金融和电信服务
遗留系统支持
公共API
简单的资源驱动型应用程序
移动APIS
复杂的系统
微服务
指挥和行动导向的API
大规模微服务系统中的高性能通信

由于主要研究的是网络安全,故我们可能更关注于请求方式、请求体中的特征是怎样的?因此,下面会着重介绍这些特征,优势和缺点我们在这里不做重点叙述。

RPC

XML-RPC

如果你对此不太了解,你可以尝试在线调试

请求方式

GET或者POST

举例

比方说,我们这里就拿wordpress举例,wordpress就是支持XML的,那如果我们想要获取wordpress下面有哪些接口,可以先通过POST请求/xmlrpc.php,请求体如下

<?xml version='1.0'?>
<methodCall>
	<methodName>system.listMethods</methodName>
</methodCall>

然后就可以看到wordpress系统中有哪些方法

<methodResponse>
    <params>
        <param>
            <value>
                <array><data>
                        <value>
                            <string>system.multicall</string>
                        </value>
                        <value>
                            <string>system.listMethods</string>
                        </value>
                        <value>
                            <string>system.getCapabilities</string>
                        </value>
                        <value>
                            <string>demo.multiplyTwoNumbers</string>
                        </value>
                        <value>
                            <string>demo.addTwoNumbers</string>
                        </value>
                        <value>
                            <string>demo.sayHello</string>
                        </value>
                        <value>
                            <string>pingback.extensions.getPingbacks</string>
                        </value>
                        <value>
                            <string>pingback.ping</string>
                        </value>
                        <value>
                            <string>mt.publishPost</string>
                        </value>
                        <value>
                            <string>mt.getTrackbackPings</string>
                        </value>
                        <value>
                            <string>mt.supportedTextFilters</string>
                        </value>
                        <value>
                            <string>mt.supportedMethods</string>
                        </value>
                        <value>
                            <string>mt.setPostCategories</string>
                        </value>
                        <value>
                            <string>mt.getPostCategories</string>
                        </value>
                        <value>
                            <string>mt.getRecentPostTitles</string>
                        </value>
                        <value>
                            <string>mt.getCategoryList</string>
                        </value>
                        <value>
                            <string>metaWeblog.getUsersBlogs</string>
                        </value>
                        <value>
                            <string>metaWeblog.setTemplate</string>
                        </value>
                        <value>
                            <string>metaWeblog.getTemplate</string>
                        </value>
                        <value>
                            <string>metaWeblog.deletePost</string>
                        </value>
                        <value>
                            <string>metaWeblog.newMediaObject</string>
                        </value>
                        <value>
                            <string>metaWeblog.getCategories</string>
                        </value>
                        <value>
                            <string>metaWeblog.getRecentPosts</string>
                        </value>
                        <value>
                            <string>metaWeblog.getPost</string>
                        </value>
                        <value>
                            <string>metaWeblog.editPost</string>
                        </value>
                        <value>
                            <string>metaWeblog.newPost</string>
                        </value>
                        <value>
                            <string>blogger.deletePost</string>
                        </value>
                        <value>
                            <string>blogger.editPost</string>
                        </value>
                        <value>
                            <string>blogger.newPost</string>
                        </value>
                        <value>
                            <string>blogger.setTemplate</string>
                        </value>
                        <value>
                            <string>blogger.getTemplate</string>
                        </value>
                        <value>
                            <string>blogger.getRecentPosts</string>
                        </value>
                        <value>
                            <string>blogger.getPost</string>
                        </value>
                        <value>
                            <string>blogger.getUserInfo</string>
                        </value>
                        <value>
                            <string>blogger.getUsersBlogs</string>
                        </value>
                        <value>
                            <string>wp.getCommentStatusList</string>
                        </value>
                        <value>
                            <string>wp.newComment</string>
                        </value>
                        <value>
                            <string>wp.editComment</string>
                        </value>
                        <value>
                            <string>wp.deleteComment</string>
                        </value>
                        <value>
                            <string>wp.getComments</string>
                        </value>
                        <value>
                            <string>wp.getComment</string>
                        </value>
                        <value>
                            <string>wp.setOptions</string>
                        </value>
                        <value>
                            <string>wp.getOptions</string>
                        </value>
                        <value>
                            <string>wp.getPageTemplates</string>
                        </value>
                        <value>
                            <string>wp.getPageStatusList</string>
                        </value>
                        <value>
                            <string>wp.getPostStatusList</string>
                        </value>
                        <value>
                            <string>wp.getCommentCount</string>
                        </value>
                        <value>
                            <string>wp.uploadFile</string>
                        </value>
                        <value>
                            <string>wp.suggestCategories</string>
                        </value>
                        <value>
                            <string>wp.deleteCategory</string>
                        </value>
                        <value>
                            <string>wp.newCategory</string>
                        </value>
                        <value>
                            <string>wp.getTags</string>
                        </value>
                        <value>
                            <string>wp.getCategories</string>
                        </value>
                        <value>
                            <string>wp.getAuthors</string>
                        </value>
                        <value>
                            <string>wp.getPageList</string>
                        </value>
                        <value>
                            <string>wp.editPage</string>
                        </value>
                        <value>
                            <string>wp.deletePage</string>
                        </value>
                        <value>
                            <string>wp.newPage</string>
                        </value>
                        <value>
                            <string>wp.getPages</string>
                        </value>
                        <value>
                            <string>wp.getPage</string>
                        </value>
                        <value>
                            <string>wp.getUsersBlogs</string>
                        </value>
                </data></array>     
            </value>
        </param>
    </params>
</methodResponse>

通过观察,我们可以看到有wp.getUserBlogs方法,那我们如何通过这个方法,对用户名、密码进行暴力破解呢?

我们可以POST请求,发送下面的内容,usernamepassword分别代表用户名、密码,由此你也可以使用fuzz模糊测试或者burpsuite对其进行暴力破解,这也是为什么很多wordpress网站需要对xmlrpc.php进行防护,甚至很多人在配置文件里将其关闭。

<?xml version='1.0'?>
<methodCall>
	<methodName>wp.getUserBlogs</methodName>
	<params>
		<param>
			<value>username</value>
		</param>
		<param>
			<value>password</value>
		</param>
	</params>
</methodCall>

JSON-RPC

如果你对此不太了解,你可以尝试在线调试。如果你之前对区块链有所耳闻,其实大多数的挖矿都是通过JSON-RPC进行请求的,我们还可以看上次我分析的文章

请求方式

GETPOST

举例

这里继续拿wordpress进行举例,下面是一个遐想的场景哦!仅用作和XML-RPC进行对比!

我们如果用JSON-RPC的方式请求刚才的接口,请求体的内容又是怎样的呢?

比方说,我们还是想获取系统下有哪些方法,那我们需要进行如下请求

{
    "methodCall": {
        "methodName": "system.listMethods",
    }
}

那如果获取到了wp.getUserBlogs,如何使用用户名、密码登录呢?

{
    "methodCall": {
        "methodName": "wp.getUserBlogs",
        "params": [
            {
                username,
                password
            }
        ]
    }
}

SOAP

请求方式

GET或者POST

请求体格式

POST请求都应该有哪些内容呢?格式如下

<?xml version="1.0"?>  
  
<soap:Envelope  
xmlns:soap="http://www.w3.org/2003/05/soap-envelope/"  
soap:encodingStyle="http://www.w3.org/2003/05/soap-encoding">  
  
<soap:Header>  
...  
</soap:Header>  
  
<soap:Body>  
...  
  <soap:Fault>  
  ...  
  </soap:Fault>  
</soap:Body>  
  
</soap:Envelope>

举例

请求URL/getAdUnitsByStatement

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope
        xmlns:soapenv="https://schemas.xmlsoap.org/soap/envelope/"
        xmlns:xsd="https://www.w3.org/2001/XMLSchema"
        xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Header>
    <ns1:RequestHeader
         soapenv:actor="https://schemas.xmlsoap.org/soap/actor/next"
         soapenv:mustUnderstand="0"
         xmlns:ns1="https://www.google.com/apis/ads/publisher/v201605">
      <ns1:networkCode>123456</ns1:networkCode>
      <ns1:applicationName>DfpApi-Java-2.1.0-dfp_test</ns1:applicationName>
    </ns1:RequestHeader>
  </soapenv:Header>
  <soapenv:Body>
    <getAdUnitsByStatement xmlns="https://www.google.com/apis/ads/publisher/v201605">
      <filterStatement>
        <query>WHERE parentId IS NULL LIMIT 500</query>
      </filterStatement>
    </getAdUnitsByStatement>
  </soapenv:Body>
</soapenv:Envelope>

我们可以看到上面的其实核心就查询语句

<query>WHERE parentId IS NULL LIMIT 500</query>

对比JSON-RPC,我们会发现上面属实繁琐太多了

下面是JSON-RPC的请求体部分

{"filter": "WHERE parentId IS NULL LIMIT 500"}

完整的POST请求包

POST /getAdUnitsByStatement HTTP/1.1
HOST: api.example.com
Content-Type: application/json

{"filter": "WHERE parentId IS NULL LIMIT 500"}

REST

请求方式

HEAD或者GET或者POST或者PUT或者PATCH或者Delete

请求方式作用
HEAD对任何资源仅请求头信息
GET获取资源
POST创建资源
PATCH使用部分的JSON数据更新资源
PUT取代资源或资源集合
DELETE删除资源

状态码

状态码描述
200 OK表示请求已经成功。
201 Created表示请求已经成功,并因此创建了一个新的资源。
202 Accepted表示已经收到请求但尚未完成。它通常用于日志运行请求和批处理。
203 Non-Authoritative Information表示返回的实体头中的元信息不是来自源服务器的确定集合,而是从本地或第三方的副本中收集的。提出的集合可能是原始版本的子集或超集。
204 No Content服务器已经完成了请求,但不需要返回响应体。服务器可以返回更新的元信息。
205 Reset Content表示客户端要重置发送此请求的文件。
206 Partial Content当客户端发送Range头时,它被用于只请求一个资源的一部分。
207 Multi-Status (WebDAV)给客户的一个指示器,表明发生了多个操作,每个操作的状态都可以在响应的正文中找到。
208 Already Reported (WebDAV)允许客户端告诉服务器相同的资源(具有相同的绑定)在前面被提及。它从不作为真正的HTTP响应代码出现在状态行中,而只出现在正文中。
226 IM Used服务器已经完成了对该资源的GET请求,并且响应是应用于当前实例的一个或多个实例处理结果的表示。

举例

请求URL

这里以某网站的API进行举例说明

请求方式URLAPI 作用
GET/api/users?page=2列出用户列表
GET/api/users/2查看某个用户信息
POST/api/users/创建用户
PUT/api/users/更新用户
PATCH/api/users/更新用户
DELETE/api/users/删除用户

请求体

如果是PUTPATCHPOST请求

URL为/api/user

{
    "name": "morpheus",
    "job": "leader"
}

总结

我们会发现请求体中也是JSON的格式,其实与JSON-RPC很像,但是这里REST风格的URL让人更容易理解了

GraphQL

请求方式

GET或者POST

举例

我们这里可以使用一个测试站点

https://countries.trevorblades.com/

然后编写我们的查询语句

上面两个在线测试站点均可以完成,我们这里使用下面的语句,尝试第一次查询

query {
  countries {
    name
  }
}
图片[2]-常见的四种API:SOAP vs RPC vs REST vs GraphQL-FancyPig's blog
图片[3]-常见的四种API:SOAP vs RPC vs REST vs GraphQL-FancyPig's blog

这里你可能会有疑问,就是在真正的请求中是怎样的呢?通常GraphQL和REST都会有一个端点,譬如/graphql

我们这里以GET请求为例,则应该是https://countries.trevorblades.com/?query={countries{name}}

这里,我可能讲解的不够细致,详细的可以参考

GrphQL官网的讲解:https://graphql.cn/learn/serving-over-http/

© 版权声明
THE END
喜欢就支持一下吧
点赞14赞赏 分享
评论 共3条

请登录后发表评论