API

一、理解RESTful架构

越来越多的人开始意识到,网站即软件,而且是一种新型的软件。

这种"互联网软件"采用客户端/服务器模式,建立在分布式体系上,通过互联网通信,具有高延时(high latency)、高并发等特点。

网站开发,完全可以采用软件开发的模式。但是传统上,软件和网络是两个不同的领域,很少有交集;软件开发主要针对单机环境,网络则主要研究系统之间的通信。互联网的兴起,使得这两个领域开始融合,现在我们必须考虑,如何开发在互联网环境中使用的软件。

RESTful架构,就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。

但是,到底什么是RESTful架构,并不是一个容易说清楚的问题。下面,我就谈谈我理解的RESTful架构。

1.1、起源

REST这个词,是Roy Thomas Fielding在他2000年的博士论文中提出的。

Fielding是一个非常重要的人,他是HTTP协议(1.0版和1.1版)的主要设计者、Apache服务器软件的作者之一、Apache基金会的第一任主席。所以,他的这篇论文一经发表,就引起了关注,并且立即对互联网开发产生了深远的影响。

他这样介绍论文的写作目的:

"本文研究计算机科学两大前沿----软件和网络----的交叉点。长期以来,软件研究主要关注软件设计的分类、设计方法的演化,很少客观地评估不同的设计选择对系统行为的影响。而相反地,网络研究主要关注系统之间通信行为的细节、如何改进特定通信机制的表现,常常忽视了一个事实,那就是改变应用程序的互动风格比改变互动协议,对整体表现有更大的影响。我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。"

(This dissertation explores a junction on the frontiers of two research disciplines in computer science: software and networking. Software research has long been concerned with the categorization of software designs and the development of design methodologies, but has rarely been able to objectively evaluate the impact of various design choices on system behavior. Networking research, in contrast, is focused on the details of generic communication behavior between systems and improving the performance of particular communication techniques, often ignoring the fact that changing the interaction style of an application can have more impact on performance than the communication protocols used for that interaction. My work is motivated by the desire to understand and evaluate the architectural design of network-based application software through principled use of architectural constraints, thereby obtaining the functional, performance, and social properties desired of an architecture. )

1.2、名称

Fielding将他对互联网软件的架构原则,定名为REST,即Representational State Transfer的缩写。我对这个词组的翻译是"表现层状态转化"。

如果一个架构符合REST原则,就称它为RESTful架构。

要理解RESTful架构,最好的方法就是去理解Representational State Transfer这个词组到底是什么意思,它的每一个词代表了什么涵义。如果你把这个名称搞懂了,也就不难体会REST是一种什么样的设计。

1.3、资源(Resources)

REST的名称"表现层状态转化"中,省略了主语。"表现层"其实指的是"资源"(Resources)的"表现层"。

所谓"资源",就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。你可以用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。

所谓"上网",就是与互联网上一系列的"资源"互动,调用它的URI。

1.4、表现层(Representation)

"资源"是一种信息实体,它可以有多种外在表现形式。我们把"资源"具体呈现出来的形式,叫做它的"表现层"(Representation)。

比如,文本可以用txt格式表现,也可以用HTML格式、XML格式、JSON格式表现,甚至可以采用二进制格式;图片可以用JPG格式表现,也可以用PNG格式表现。

URI只代表资源的实体,不代表它的形式。严格地说,有些网址最后的".html"后缀名是不必要的,因为这个后缀名表示格式,属于"表现层"范畴,而URI应该只代表"资源"的位置。它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现层"的描述。

1.5、状态转化(State Transfer)

访问一个网站,就代表了客户端和服务器的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。

互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。

客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议里面,四个表示操作方式的动词:GET、POST、PUT、DELETE。它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

1.6、综述

综合上面的解释,我们总结一下什么是RESTful架构:

  • 每一个URI代表一种资源;

  • 客户端和服务器之间,传递这种资源的某种表现层;

  • 客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。

1.7、误区

RESTful架构有一些典型的设计误区。

最常见的一种设计错误,就是URI包含动词。因为"资源"表示一种实体,所以应该是名词,URI不应该有动词,动词应该放在HTTP协议中。

举例来说,某个URI是/posts/show/1,其中show是动词,这个URI就设计错了,正确的写法应该是/posts/1,然后用GET方法表示show。

如果某些动作是HTTP动词表示不了的,你就应该把动作做成一种资源。比如网上汇款,从账户1向账户2汇款500元,错误的URI是:

POST /accounts/1/transfer/500/to/2

正确的写法是把动词transfer改成名词transaction,资源不能是动词,但是可以是一种服务:

POST /transaction HTTP/1.1
Host: 127.0.0.1
from=1&to=2&amount=500.00

另一个设计误区,就是在URI中加入版本号:

http://www.example.com/app/1.0/foo
http://www.example.com/app/1.1/foo
http://www.example.com/app/2.0/foo

因为不同的版本,可以理解成同一种资源的不同表现形式,所以应该采用同一个URI。版本号可以在HTTP请求头信息的Accept字段中进行区分(参见Versioning REST Services):

Accept: vnd.example-com.foo+json; version=1.0
Accept: vnd.example-com.foo+json; version=1.1
Accept: vnd.example-com.foo+json; version=2.0

二、RESTful API 设计指南

网络应用程序,分为前端和后端两个部分。当前的发展趋势,就是前端设备层出不穷(手机、平板、桌面电脑、其他专用设备......)。

因此,必须有一种统一的机制,方便不同的前端设备与后端进行通信。这导致API构架的流行,甚至出现"API First"的设计思想。RESTful API是目前比较成熟的一套互联网应用程序的API设计理论。我以前写过一篇《理解RESTful架构》,探讨如何理解这个概念。

今天,我将介绍RESTful API的设计细节,探讨如何设计一套合理、好用的API。

2.1、协议

API与用户的通信协议,总是使用HTTPs协议。

2.2、域名

应该尽量将API部署在专用域名之下。

https://api.example.com

如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下。

https://example.org/api/

2.3、版本(Versioning)

应该将API的版本号放入URL。

https://api.example.com/v1/

另一种做法是,将版本号放在HTTP头信息中,但不如放入URL方便和直观。Github采用这种做法。

2.4、路径(Endpoint)

路径又称"终点"(endpoint),表示API的具体网址。

在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数。

举例来说,有一个API提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样。

https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees

2.5、HTTP动词

对于资源的具体操作类型,由HTTP动词表示。

常用的HTTP动词有下面五个(括号里是对应的SQL命令)。

  • GET(SELECT):从服务器取出资源(一项或多项)。

  • POST(CREATE):在服务器新建一个资源。

  • PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。

  • PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。

  • DELETE(DELETE):从服务器删除资源。

还有两个不常用的HTTP动词。

  • HEAD:获取资源的元数据。

  • OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。

下面是一些例子。

  • GET /zoos:列出所有动物园

  • POST /zoos:新建一个动物园

  • GET /zoos/ID:获取某个指定动物园的信息

  • PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)

  • PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)

  • DELETE /zoos/ID:删除某个动物园

  • GET /zoos/ID/animals:列出某个指定动物园的所有动物

  • DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

2.6、过滤信息(Filtering)

如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。

下面是一些常见的参数。

  • ?limit=10:指定返回记录的数量

  • ?offset=10:指定返回记录的开始位置。

  • ?page=2&per_page=100:指定第几页,以及每页的记录数。

  • ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。

  • ?animal_type_id=1:指定筛选条件

参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如,GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的。

2.7、状态码(Status Codes)

服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。

  • 200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。

  • 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。

  • 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)

  • 204 NO CONTENT - [DELETE]:用户删除数据成功。

  • 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。

  • 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。

  • 403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。

  • 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。

  • 406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。

  • 410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。

  • 422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。

  • 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。

状态码的完全列表参见这里

2.8、错误处理(Error handling)

如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。

{
    error: "Invalid API key"
}

2.9、返回结果

针对不同操作,服务器向用户返回的结果应该符合以下规范。

  • GET /collection:返回资源对象的列表(数组)

  • GET /collection/resource:返回单个资源对象

  • POST /collection:返回新生成的资源对象

  • PUT /collection/resource:返回完整的资源对象

  • PATCH /collection/resource:返回完整的资源对象

  • DELETE /collection/resource:返回一个空文档

2.10、Hypermedia API

RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。

比如,当用户向api.example.com的根目录发出请求,会得到这样一个文档。

{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

上面代码表示,文档中有一个link属性,用户读取这个属性就知道下一步该调用什么API了。rel表示这个API与当前网址的关系(collection关系,并给出该collection的网址),href表示API的路径,title表示API的标题,type表示返回类型。

Hypermedia API的设计被称为HATEOAS。Github的API就是这种设计,访问api.github.com会得到一个所有可用API的网址列表。

{
  "current_user_url": "https://api.github.com/user",
  "authorizations_url": "https://api.github.com/authorizations",
  // ...
}

从上面可以看到,如果想获取当前用户的信息,应该去访问api.github.com/user,然后就得到了下面结果。

{
  "message": "Requires authentication",
  "documentation_url": "https://developer.github.com/v3"
}

上面代码表示,服务器给出了提示信息,以及文档的网址。

2.11、其他

  • API的身份认证应该使用OAuth 2.0框架。

  • 服务器返回的数据格式,应该尽量使用JSON,避免使用XML。

三、API 开发工具

3.1、Apizza

国内领先的在线 API saas 管理平台,支持在线的 API 调试,接口管理,快速生成文档,项目管理以及分享。

Apizza 平台分为开发模式和浏览模板,开发模式只有用户自己可以打开,浏览模式是供其他人查看,测试使用。

转存失败重新上传取消

平台支持标准的http协议请求,支持添加header,支持标准 json,xml,html,text四种返回格式, 自动格式化展示。

平台做了许多体验优化,比如参数列表和url自动转换, 请求文档字段一键生成。

响应文档的字段可以从api返回自动生成。请求自动存为历史记录, 支持定义的环境变量,可以方便切换线下,下上环境,文档导出等等。

下面就简单介绍下怎么使用 Apizza 进行接口测试。

①、第一步:准备接口

<?php
   namespace Home\Controller;
   use Think\Controller;
   class ApiController extends Controller {
     public function index(){
       $result = array(
             "status"=>1,
             "data"=>array(
               "name"=>"My name",
               "tel"=>"12345678",
             )
         );
       header("Content-Type: application/json");
      echo json_encode($result);
   }
}

②、第二步:测试接口

登陆Apizza,创建一个新项目,进入控制台,填写接口地址,并点击发送,效果如图

 

转存失败重新上传取消

转存失败重新上传取消

可以看出,效果不错!

接下来测试一下传递参数的情况

<?php namespace Home\Controller;
use Think\Controller;
class ApiController extends Controller {
    public function index(){
    $requests = I();
    $result = array(
        "status"=>1,
        "data"=>$requests
    );
    header("Content-Type: application/json");
    echo json_encode($result);
    }
}

测试效果图如下

 转存失败重新上传取消

测试效果和展示效果都还不错,而且直观,简洁。

③、第三步:写文档

Apizza可以方便的写文档,只要一个按钮就可以把模拟的字段自动生成文档字段。 这个功能还是很方便的。

 

点击那个U的按钮,可以自动生成红色框里面的字段,你只要把说明补充上就行了。最后点击保存。

④、第四步:导出文档

这个功能不错,导出的文档格式也很漂亮。如下图

 

好了,基本介绍了Apizza的使用流程,他还有许多其他的功能,这里没有做介绍,可以自己 去体会一下,最后补充一下,要使用 apizza,需要按照他的 chrome 插件,这个主要是做跨域的, 不然不能使用哦^_^

3.2、showdoc

 

showdoc 网站打开看着不起眼,但里面的内容相当的强大,重点说下特点

  • 1:支持markdown语法(所有的api接口写作现在都支持这个吧,因为他现在太方便了)

  • 2:支持多用户协作,你可以在项目下面随意添加多个用户一起完成api文档的写作。

  • 3:可以分享并导出项目,生成需要的文档格式如doc,可以离线浏览

  • 4:支持响应式,手机电脑同样精彩

  • 5:支持项目转让

  • 6:支持模版插入

  • 7:支持历史版本,你可以把操作恢复到以前的版本。

  • 8:showdoc完全开源

  • 9:可以部署到自己的服务器

  • 10:如果在线使用,可以设置自己的个性域名,也可以对文档进行加密,浏览者需要密码才能访问

  • 11:可以通过一个在线测试api的工具,直接生成markdown,你几乎不用写代码就能过所有的参数自动生成

看一些页面:

 

 

3.3、PostMan

Postman 是 google 开发的一款功能强大的网页调试与发送网页 HTTP 请求,并能运行测试用例的的 Chrome 插件。

3.3.1、主要功能

①、模拟各种HTTP requests

从常用的 GET、POST 到 RESTful 的 PUT 、 DELETE …等等。 甚至还可以发送文件、送出额外的 header。

②、Collection 功能(测试集合)

Collection 是 requests的集合,在做完一個测试的時候, 你可以把這次的 request 存到特定的 Collection 里面,如此一來,下次要做同样的测试时,就不需要重新输入。而且一个collection可以包含多条request,如果我们把一个request当成一个test case,那collection就可以看成是一个test suite。通过collection的归类,我们可以良好的分类测试软件所提供的API.而且 Collection 还可以 Import 或是 Share 出來,让团队里面的所有人共享你建立起來的 Collection。

③、人性化的Response整理

一般在用其他工具來测试的時候,response的内容通常都是纯文字的 raw, 但如果是 JSON ,就是塞成一整行的 JSON。这会造成阅读的障碍 ,而 Postman 可以针对response内容的格式自动美化。 JSON、 XML 或是 HTML 都會整理成我们可以阅读的格式

④、内置测试脚本语言

Postman支持编写测试脚本,可以快速的检查request的结果,并返回测试结果

⑤、设定变量与环境

Postman 可以自由 设定变量与Environment,一般我们在编辑request,校验response的时候,总会需要重复输入某些字符,比如url,postman允许我们设定变量来保存这些值。并且把变量保存在不同的环境中。比如,我們可能会有多种环境, development 、 staging 或 local, 而这几种环境中的 request URL 也各不相同,但我们可以在不同的环境中设定同样的变量,只是变量的值不一样,这样我们就不用修改我们的测试脚本,而测试不同的环境。

3.3.2、安装Postman

①、Postman 作为一个 chrome 的插件,你可以打开 chrome,在 chrome webstore里面找到。

②、安装完成后,你可以不用打开 chrome 而直接使用 Postman,具体的方法是:

选项->更多工具->扩展程序

01.png

详细信息->创建快捷方式->‘全部勾上’

02.png

这样你就可以在任何地方启动你的 Postman 了。

3.3.3、Postman sending requests

安装好之后,我们先打开 Postman,可以看到界面分成左右两个部分,右边是我们后头要讲的 collection,左边是现在要讲的 request builder。在 request builder 中,我们可以通过 Postman 快速的随意组装出我们希望的 request。

一般来说,所有的 HTTP Request 都分成 4 个部分,URL, method, headers 和 body。而 Postman 针对这几部分都有针对性的工具。

 

03.png

①、URL

要组装一条 Request, URL 永远是你首先要填的内容,在 Postman 里面你曾输入过的 URL 是可以通过下拉自动补全的哦。如果你点击 Params 按钮,Postman 会弹出一个键值编辑器,你可以在哪里输入URL 的 Parameter,Postman 会帮你自动加入到 URL 当中,反之,如果你的 URL 当中已经有了参数,那 Postman 会在你打开键值编辑器的时候把参数自动载入。

04.png

②、Headers

点击 Headers 按钮,Postman 同样会弹出一个键值编辑器。在这里,你可以随意添加你想要的 Header attribute,同样 Postman 为我们通过了很贴心的 auto-complete 功能,敲入一个字母,你可以从下拉菜单里选择你想要的标准 atrribute

05.png

③、Method

要选择 Request 的 Method 是很简单的,Postman 支持所有的 Method,而一旦你选择了 Method,Postman 的 request body 编辑器会根据的你选择,自动的发生改变。

06.png

④、Request Body

如果我们要创建的 request 是类似于 POST,那我们就需要编辑 Request Body,Postman 根据 body type 的不同,提供了 4 种编辑方式:

form-data、x-www-form-urlencoded、raw、binary

07.png

3.3.4、演示

我这里创建一条发送给 baidu 的request

http://api.map.baidu.com/telematics/v2/weather?location=%E4%B8%8A%E6%B5%B7&ak=B8aced94da0b345579f481a1294c9094

点击了 Send 之后,可以在 Postman 上直接看到 response 的内容,内容很漂亮。

Postman 根据内容检索自动按 XML 的格式显示出来,同时我们可以清楚的看到 status code 和花费的时间。

08.png

 

3.4、PhalApi

PhalApi是一个PHP轻量级开源接口框架,致力于快速开发接口服务。支持HTTP/SOAP/RPC等协议,可用于搭建接口/微服务/RESTful接口/Web Services。

 

五、测试利器——jmeter

5.1、介绍(需要先安装java)

Apache JMeter是Apache组织开发的基于Java的压力测试工具。用于对软件做压力测试,它最初被设计用于Web应用测试,但后来扩展到其他测试领域。

5.2、下载

打开链接,找到下图

01.png

打开 bin/jmeter.bat 即可使用。

5.3、测试

①、新建线程组

01.png

07.png

②、新建 http 请求

02.png

03.png

01.png

02.png

③、新建察看结果树

04.png

④、开始测试

05.png

06.png

六、设计基于HTML5的APP登录功能及安全调用接口的方式(原理篇)

6.1、你是否真的需要登录功能?

把这个问题放在最前面并不是灌水,而是真的见过很多并不需要登录的APP去做了登录功能,或者是并不需要强制登录的APP把登录作为启动页。

用户对你的APP一无所知,你就要求对方注册并登录,除非APP本身已经很有名气或者是用户有强需求,否则正常人应该会直接把它删掉。

比较温和的方式是将一些并不需要登录,但可以给用户带来帮助的东西,第一时间展现给他们,让他们产生兴趣,再在合适的时机引导他们注册(比如使用需要使用更高级的功能,或用户需要收藏某个喜欢的信息时)。

6.2、登录和注册要足够简单

这是小小的手机端,用再好的输入法,打字也是不方便的,所以别把登录页设计得需要填很多东西。

如果有可能的话,只填手机号,让用户收到短信验证码就完成注册是最好不过的了。

想获得更多信息?想想大公司的APP是怎么做的,他们会告诉用户,现在的个人资料完善程度是30%,如果想获得更多积分,你需要填完。

tips:如果你想发布在Appstore并且同时包含注册功能,那么注册页面必须做一个用户许可协议的链接,否则有可能通不过审核。

6.3、实现登录后的session有几种方式?

①、APP当浏览器用,直接载入远程页面

这种情况是很多偷懒的程序员或者傻X的老板选择的方式,因为做起来实在太快。

如果本身网站是响应式布局,那么很有可能不需要做什么更改,就只要在开发时打开首页就好了,这样Hybird的APP外壳就纯粹成为了一个浏览器。

但比起这样做带来的无数缺点来,开发速度快的优点几乎可以忽略不计。首先,在网络环境不佳时,纯大白页,用户体验0;

然后,CSS和JS等资源不在本地,需要远程载入,如果使用了bootstrap之类的框架,那用户为了开一下APP而耗费的流量真是令人感动;

再然后,网页里常用的jquery,在手机的webview里速度并不理想,而如果是非ajax的网页那就更糟心了,每次操作都要跳转和页面渲染,要让人把它当成APP那实在是笑话。

再再然后,这样的所谓APP,要通过Appstore的审查,那是做梦的(除非审核员当天闹肚子严重,拿着纸巾奔向厕所前误点了通过……),苹果的要求是,这得是APP,而不能是某个网站做成APP的样子,那样的情况适合做Web APP。而据我所知,国内几个较大的Android市场,这样的APP也是无法通过审核的。

②、调用后端接口

这是个很好的时代,因为无论后端你是用Java、PHP,还是node.js,都可以通过xml、json来和APP通讯。遥想当年写服务端要自己写包结构,然后为了解决并发问题还折腾了半年IOCP模型,真心觉得现在太幸福了。

把刚才那个用APP当浏览器使的案例的所有缺点反过来看,就是这样做的优点,在优化完善的情况下体验接近原生,而且通讯流量极少,通过各种审核也是妥妥的。

tips:通过plus对象中的XMLHttpRequest来Get、Post远程的后端接口。

6.4、调用后端接口怎么样才安全?

①、在APP中保存登录数据,每次调用接口时传输

程序员总能给自己找到偷懒的方法,有的程序为了省事,会在用户登录后,直接把用户名和密码保存在本地,然后每次调用后端接口时作为参数传递。真省事儿啊!可这种方法简单就像拿着一袋子钱在路上边走边喊“快来抢我呀!快来抢我呀!”,一个小小的嗅探器就能把用户的密码拿到手,如果用户习惯在所有地方用一个密码,那么你闯大祸了,黑客通过撞库的方法能把用户的所有信息一锅端。

②、登录时请求一次token,之后用token调用接口

这是比较安全的方式,用户在登录时,APP调用获取token的接口(比如http://api.abc.com/get_token/),用post将用户名和密码的摘要传递给服务器,然后服务器比对数据库中的用户信息,匹配则返回绑定该用户的token(这一般翻译为令牌,很直观的名字,一看就知道是有了这玩意,就会对你放行),而数据库中,在用户的token表中也同时插入了这个token相关的数据:这个token属于谁?这个token的有效期是多久?这个token当前登录的ip地址是?这个token对应的deviceid是?……

这样即便token被有心人截获,也不会造成太大的安全风险。因为没有用户名和密码,然后如果黑客通过这个token伪造用户请求,我们在服务器端接口被调用时就可以对发起请求的ip地址、user-agent之类的信息作比对,以防止伪造。再然后,如果token的有效期设得小,过一会儿它就过期了,除非黑客可以持续截获你的token,否则他只能干瞪眼。(插一句题外话:看到这里,是不是明白为什么不推荐在外面随便接入来历不明的wifi热点了?)

  • tips:token如何生成? 可以根据用户的信息及一些随机信息(比如时间戳)再通过hash编码(比如md5、sha1等)生成唯一的编码。

  • tips:token的安全级别,取决于你的实际需求,所以如果不是涉及财产安全的领域,并不建议太严格(比如用户走着走着,3G换了个基站,闪断了一下IP地址变了,尼玛token过期了,这就属于为了不必要的安全丢了用户体验,当然如果变换的IP地址跨省的话还是应该验证一下的,想想QQ有时候会让填验证码就明白了)。

  • tips:接口在返回信息时,可以包含本次请求的状态,比如成功调用,那么result['status']可能就是'success',而反之则是'error',而如果是'error',则result['errcode']中就可以包含错误的原因,比如errcode中是'invalid_token'就可以告诉APP这个token过期或无效,这时APP应弹出登录框或者用本地存储的用户名或密码再次请求token(用户选择“记住密码”,就应该在本地保存用户名和密码的摘要,方法见plus.storage的文档)。

③、更安全一点,获取token通过SSL

刚才的方法,机智一点儿的读者大概会心存疑虑:那获取token时不还是得明文传输一次密码吗?

是的,你可以将这个获取token的地址,用SSL来保护(比如https://api.abc.com/get_token/),这样黑客即使截了包,一时半会儿也解不出什么信息。

SSL证书的获取渠道很多,我相信你总有办法查到,所以不废话了。不过话说namecheap上的SSL证书比godaddy的要便宜得多……(这是吐槽)

  • tips:前段时间OpenSSL漏洞让很多服务器遭殃,所以如果自己搭服务器,一定记得装补丁。

  • tips:可以把所有接口都弄成SSL的吗?可以。但会拖慢服务器,如果是配置并不自信的VPS,建议不折腾。

  • tips:苹果商店从2017年1月开始需要用SSL API。

④、还要更更安全(这标题真省事)

还记得刚才APP向服务器请求token时,可以加入的用户信息吗?比如用户的设备deviceid。

如果我们在调用接口时,还附带一个当前时间戳参数timestamp,同时,用deviceid和这个时间戳再生成一个参数sign,比如 sign=md5(deviceid timestamp token)这样的形式。而服务端根据用户传递过来的token、timestamp和保存在服务器中的deviceid进行md5加密生成sign,验证是否等于传递过来的sign,那便自然“更更安全”了。

  • tips:明白了原理,整个验证过程是可以根据自己的需求改造的。

七、开发日志

7.1、往文件中写入日志

①、在线可访问页面

<?php
if(isset($_GET["start"])){
    define("IA_ROOT", str_replace("\\", "/", dirname(__FILE__)));
    $lines = file("logs/".date("Y-m-d").".log");
    $start = !empty($_GET["start"])?intval($_GET["start"]):0;
    $str = "";
    $count = count($lines);
    if($start < $count){
        $str.="<br><hr><br>";
        for($i=$start;$i<$count;$i++){
            $str.=$lines[$i];
        }
    }
    !empty($str) && $str = str_replace("\r\n","<br>",$str);
    echo json_encode(array(
        "content"=>$str,
        "lines"=>$count
    ));
    exit;
}
?>
<div id="content"></div>
<script lay-src="jquery.min.js" type="text/javascript"></script>
<script>
    var start = 0;
    function get_content(){
        $.ajax({
            type: "get",
            url: window.location.href+"?start="+start,
            dataType: "json",
            success: function(res) {
                if(res!=""){
                    start = res.lines;
                    var d1 = document.getElementById("content");
                    d1.insertAdjacentHTML("beforeEnd", res.content);
                    goToWhere(1);
                }
                setTimeout(function(){
                    get_content();
                },5000);
            },
            error: function(){
                console.log("网络错误");
            }
        });
    }
    get_content();
    function goToWhere(where){
        var me = this;
        me.site = [];
        me.sleep = me.sleep ? me.sleep : 16;
        me.fx = me.fx ? me.fx : 6;
        clearInterval (me.interval);
        var dh = document.documentElement.scrollHeight || document.body.scrollHeight;
        var height = !!where ? dh : 0;
        me.interval = setInterval (function (){
            var top = document.documentElement.scrollTop || document.body.scrollTop;
            var speed = (height - top) / me.fx;
            if (speed === me.site[0]){
                window.scrollTo (0, height);
                clearInterval (me.interval);
            }
            window.scrollBy (0, speed);
            me.site.unshift (speed);
        }, me.sleep);
    };
</script>

②、写入日志

function addLog($logMsg = "",$logType="info")
{
    $logMsg = is_array($logMsg)? var_export($logMsg,true):$logMsg;
    $file = "logs/".date("Y-m-d").".log";
    if(!file_exists($file)){
        fopen($file,"w");
    }
    file_put_contents($file,"[".date("Y-m-d H:i:s")."][".$logType."]".$logMsg."\r\n",FILE_APPEND);
}
addLog("xxxxxxxxxx");

 

、抓包工具

8.1、Charles 抓包使用教程

①、下载

下载地址

②、破解

01.png

Mac OS、6BACE69077E6DA3993

③、使用

A、关闭Windows Proxy,否则打开浏览器会报错

01.png

01.png

B、设置代理端口号,一般设置 8889

01.png

C、设置 SSL 通配符

01.png

D、手机安装证书

01.png

打开手机浏览器,输入 chls.pro/ssl。(苹果手机安装后还需设置允许证书)

E、开始抓包

  • 手机连接电脑发出来的 wifi(同一个网断即可)

  • 设置 wifi 代理,找到 wifi ,点击代理,输入电脑的 ip 和刚刚设置的代理端口号 8889

  • 打开 app,开始抓包!!

01.jpg

F、Charles设置代理之后,为什么电脑和手机都不能上网

  • 造成这种问题的原因就是charles等代理工具也拦截了电脑网页的请求,但是使用的是charles代理工具的证书,导致浏览器无法验证此网页的证书,进而导致了报错。

  • 解决方法:我们只需要将charles的证书添加到电脑的信任证书中即可。

进入Charles的Help中,选择SSL Proxying,然后点击Install Charles Root Certificate。

01.png

此时我们的Charles证书是不被系统信任的,所以访问网站每回都会报证书问题,然后我们点击安装证书。

01.png

可以选择证书的安装位置,我选择的是本地计算机,所有用户都可以用,或者为了安全,也可以选择只给当前用户安装,那么别的windows用户就没有被安装此证书;

01.png

然后为证书选择存储位置,这里必须手动选择存储位置,否则自动选择出来的证书位置仍然是不被信任的。

01.png

然后点击浏览,我们手动指定证书的存储位置为“受信任的根证书颁发机构”。

 

01.png

然后点击确定,完成,此时再次进入安装证书的步骤,我们就发现Charles证书已经被系统信任。

 

01.png

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值