每一个计算机的概念,都相当的抽象、不好理解,只有在实际应用上、才能逐步深入理解。当我自学一些API的相关知识的时候,走了一些弯路,网上页没有写的比较详细的文章。记得我初干程序员的时候,面试官问我,http有几种请求?我说:“回答了有两个,get和post请求”。然后他说:“还有put”。我当时懵圈了,那时候经验少,不知道的东西也多。面试过后,回家在网上查资料,才了解put请求,它是属于RESTful的设计请求。直到今日,我个人认为官方存在的就3个请求,head请求、get、post。
为什么这么说呢?我会在下文中进行介绍,这篇文章也是我对以前知识的一个简单总结,这篇文章讲的是API,但http请求是必不可少的。
API的概念
API(Application Programming Interface,应用程序编程接口)
是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。
header请求
header其实是浏览器请求服务器的头信息
请求头HTML代码如下
<!DOCTYPE html>
<head>
<script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.0.js">
</script>
</head>
<div>11111</div>
<script type="text/javascript">
window.onload = function() {
$.ajax({
type: "GET",
url: "http://localhost/test.php",
success: function(data) {
console.log(data);
},
beforeSend: function(xhr) {
xhr.setRequestHeader("token", "qidong")
}
});
}
</script>
在PHP7中可以用getallheaders
接收信息注意PHP版本过低的只能接收来自apache的请求头信息。也可用$_SERVER['HTTP_你设定参数']
获取。
返回头用PHP的header()
函数设定,header也是可以设定允许跨与请求的。代码如下
header('Access-Control-Allow-Origin: *');
header("Access-Control-Allow-Headers: token,Origin, X-Requested-With, Content-Type, Accept");
header('Access-Control-Allow-Methods: POST,GET');
php也可以自定义返回头传递中文、让ajax解析
前端代码
$.ajax({
url:'/admin/index/getUserRegisterRecord',
data:'',
dataType:'json',
type:'get',
success:function(result){
userInfo(result);
},error:function(error){
console.log(error);
console.log(decodeURI(error.getResponseHeader('error-msg')));
console.log(error.getAllResponseHeaders());
}
});
php代码
public function getUserRegisterRecord()
{
header("error-msg :".urlencode("任务被拒绝"));
header("HTTP/1.1 403 Forbidden");
// return json("aaa",403);
die;
....
...
}
代码中利用urlencode进行转换、因为中文在http头是不识别的、然后利用
console.log(decodeURI(error.getResponseHeader('error-msg')));
进行转义回来。
关于其他的http请求头的属性
1.Request Method: GET
表明这是何种类型的请求. 最常见的请求类型有 GET
, POST
和 HEAD
,PUT
,DELETE
.
2.Host
一个HTTP请求会发送至一个特定的IP地址,但是大部分服务器都有在同一IP地址下托管多个网站的能力,那么服务器必须知道浏览器请求的是哪个域名下的资源。
Host
:www.solo365.cn
这只是基本的主机名,包含域名和子级域名。
在PHP中,可以通过$_SERVER['HTTP_HOST']
或 $_SERVER['SERVER_NAME']
来查看。
3.User-Agent
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.113 Safari/537.36
这个头部可以携带如下几条信息:
浏览器名和版本号.
操作系统名和版本号.
默认语言.
这就是某些网站用来收集访客信息的一般手段。例如,你可以判断访客是否在使用手机访问你的网站。
4.Accept-Language
Accept-Language : zh-CN,zh; q=0.8
这个信息可以说明用户的默认语言设置。如果网站有不同的语言版本,那么就可以通过这个信息来重定向用户的浏览器。
它可以通过逗号分割来携带多国语言。第一个会是首选的语言,其它语言会携带一个“q”值,来表示用户对该语言的喜好程度(0~1)。
5.Accept-Encoding
Accept-Encoding:gzip, deflate, br
大部分的现代浏览器都支持gzip压缩,并会把这一信息报告给服务器。这时服务器就会压缩过的HTML发送给浏览器。这可以减少近80%的文件大小,以节省下载时间和带宽。
PHP有Gzip这个相关扩展。
6.Last-Modified 这个属于响应不属请求属性
在浏览器第一次请求某一个URL时,服务器端的返回状态会是200,内容是客户端请求的资源,同时有一个Last-Modified的属性标记此文件在服务器端最后被修改的时间。
拿新浪网举例
Last-Modified
格式类似这样:
Last-Modified : Fri, 15 Sep 2017 05:18:53 GMT
客户端第二次请求此URL时,根据HTTP协议的规定,浏览器会向服务器传送If-Modified-Since报头,询问该时间之后文件是否有被修改过:
If-Modified-Since : Fri, 15 Sep 2017 05:18:53 GMT
如果服务器端的资源没有变化,则自动返回 HTTP 304(Not Changed.)状态码,内容为空,这样就节省了传输数据量。当服务器端代码发生改变或者重启服务器时,则重新发出资源,返回和第一次请求时类似。从而保证不向客户端重复发出资源,也保证当服务器有变化时,客户端能够得到最新的资源。
7.If-Modified-Since 它属于第二次请求出现的属性
如果一个页面已经在你的浏览器中被缓存,那么你下次浏览时浏览器将会检测文档是否被修改过,那么它就会发送这样的头部:
If-Modified-Since: Fri, 15 Sep 2017 05:18:53 GMT
如果自从这个时间以来未被修改过,那么服务器将会返回“304 Not Modified”,而且不会再返回内容。浏览器将自动去缓存中读取内容
在PHP中,可以用$_SERVER['HTTP_IF_MODIFIED_SINCE'] 来检测。
8.Cookie
顾名思义,他会发送你浏览器中存储的Cookie信息给服务器。
Cookie: PHPSESSID=r2t5uvjq435r4q7ib3vtdjq120; foo=bar
它是用分号分割的一组名值对。Cookie也可以包含session id。
在PHP中,单一的Cookie可以访问$_COOKIE
数组获得。你可以直接用$_SESSION array
获取session
变量。如果你需要session id,那么你可以使用session_id()
函数代替cookie。
9.Referer
Referer https://www.baidu.com/link?url…4880600010b070000000359bf6418
Referer 首部包含了当前页面的来源页面的地址,当前页面是通过此页面里的链接而进入的。Referer 首部允许服务器端识别是从哪里访问到它们的,可能会用此数据来进行统计分析、记录日志以及优化缓存策略等等。
需要注意的是 referer 实际上是 “referrer” 误拼写。参见 HTTP referer on Wikipedia (HTTP referer 在维基百科上的条目)来获取更多的详细信息(大陆需要翻墙)。
Referer 首部拥有暴露用户的浏览历史的潜在性,涉及到用户的隐私问题。
在以下两种情况下,Referer 不会被发送:
来源页面采用的协议为表示本地文件的 “file” 或者 “data” URI;
当前请求采用的是非安全协议,而来源页面采用的是安全协议(HTTPS)。
更多请求属性 https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers这里查看
如果你是做手机app或者小程序、或者混合开发比较常用header请求,post和get就很正常了,随着web发展,也不仅仅做网站,还有手机应用(混合应用)。这几年Android和ios的程序员不好找工作了,原因有人数多、还有就是做手机应用被混合开发挤兑的,前端用的就是html页面,原生应用没有什么优势了。淘宝和京东的app用的就是混合开发
混合开发
混合开发怎么说呢?就是外面套了一个层壳,这层壳就是原生应用代码包裹,里面其实是html,而这层外壳一些工具都帮你封装好了,直接打包就可以,最著名的就是Hbuilder,其次还有WeX5等,WeX5内部语法是自己设定的,和微信小程序类似。
下面用两张图片了解一下打包和混合应用
传统的网站是页面展现层View是和后台代码是放在一起的。而手机端的app是和服务器分离的,请求数据都是以api的方式,用ajax异步进行加载,而这两年用的最火的是RESTful风格的api。
REST、它首次出现在 2000 年 Roy Fielding 的博士论文中,他是 HTTP 规范的主要编写者之一。在目前主流的三种Web服务交互方案中,REST相比于SOAP以及XML-RPC更加简单明了,REST倾向于用更加简单轻量的方法设计和实现。REST并没有一个明确的标准,而更像是一种设计的风格。
REST 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。
RESTful 本质 :就是一种软件风格
RESTful 核心:面向资源(这里的资源是指:网络上的一个实体,这个实体可能是图片、视频、音乐,或者是一条具体的信息)
RESTful初学者可以参考豆瓣API,英文好的可以参考github的API它是完全按照REST设计的。
然而每个人对RESTful的设计不太一样,有的是为了更加的简洁,url符合RESTful而请求方式就用get和post,严格意义上说REST包涵(GET,POST,PUT,PATCH,DELETE,HEAD,OPTIONS)。
常用的前5种
GET(SELECT)
:从服务器取出资源(一项或多项)。POST(CREATE
):在服务器新建一个资源。PUT(UPDATE)
:在服务器更新资源(客户端提供改变后的完整资源)。PATCH(UPDATE)
:在服务器更新资源(客户端提供只改变的属性)。DELETE(DELETE)
:从服务器删除资源。
关于put和patch两种请求 有的人设计只用PUT 废弃PATCH。
不常用的两种
OPTIONS
:请求查询服务器的性能,或者查询与资源相关的选项和需求,例如:获取服务器对资源进行那些操作,或者访问次数等参数,在OPTIONS请求的Response中会包含Allow头信息,比如:Allow: GET HEAD 。在谷歌浏览器中跨域请求,分简单请求和复杂请求,如果是复杂请求或先发送个OPTIONS请求。
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS,PATCH;
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
Resetful Api设计
<script src="http://c.csdnimg.cn/public/common/libs/jquery/jquery-1.11.1.min.js"></script>
<script>
$.ajax({
url: 'http://api.zlzkj.com/admins/1',
type: 'DELETE',
dataType: 'JSON'
});
</script>
</body>
</html>
在http://127.0.0.1/api/web/下访问http://api.zlzkj.com/admins/1会发现Request Method过滤成OPTINOS方式了,正常应该是DELETE方式,引起了服务器的405 Method Not Allowed
在跨域的时候,浏览器会自动发起一个OPTIONS请求。当你的服务器响应了OPTIONS请求的时候,会有类似如下的响应
Allow → GET,HEAD,POST,OPTIONS,TRACE
Cache-Control → max-age=86400
Connection → keep-alive
Content-Encoding → gzip
Content-Length → 20
Content-Type → text/html
Date → Thu, 30 Jun 2016 04:00:24 GMT
Expires → Fri, 01 Jul 2016 04:00:24 GMT
Server → bfe/1.0.8.14
Vary → Accept-Encoding,User-Agent
如果你的服务器没有处理响应OPTIONS,会有如下的响应:
Connection → keep-alive
Content-Encoding → gzip
Content-Type → text/html
Date → Thu, 30 Jun 2016 04:02:35 GMT
Server → nginx/1.4.6 (Ubuntu)
Transfer-Encoding → chunked
可以看出,缺少了Allow响应头
所以,你应该有处理这个OPTIONS请求的服务,这个可以直接用nginx做,
在配置中,加一下如下的配置:
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type';
return 204;
}
HEAD
:请求用于获取某个资源的元数据(metadata)–比如,该资源是否存在,创建时间和格式,该资源的内容长度是多少,是资源的简要信息。
RESTful的URL
每个网址代表一种资源,所以网址中不能有动词,只能有名词。一般来说api中的名词应该使用复数。
举例: 有一个API提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样
GET https://api.example.cn/v1/zoos
列出所有动物园
POST https://api.example.cn/v1/zoos
新建一个动物园
GET https://api.example.cn/v1/zoos/ID
获取某个指定动物园的信息
PUT https://api.example.cn/v1/zoos/ID
更新某个指定动物园的信息(提供该动物园的全部信息)
PATCH https://api.example.cn/v1/zoos/ID
更新某个指定动物园的信息(提供该动物园的部分信息)
DELETE https://api.example.cn/v1/zoos/ID
删除某个动物园
GET https://api.example.cn/v1/zoos/ID/animals
列出某个指定动物园的所有动物
DELETE https://api.example.cn/v1/zoos/ID/animals/ID
删除某个指定动物园的指定动物
这里的V1所指的是版本号 ,是设计之时为了以后业务扩展v2.v3等。
关于过滤信息
资源的过滤信息
?limit=10:指定返回记录的数量
?offset=10:指定返回记录的开始位置。
?page=2&size=10:指定第几页,以及每页的记录数。
?user=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
?type_id=1:指定筛选条件
例如:https://api.example.cn/v1/zoos?limit=10
返回结果
返回结果都是以json的形式返回,但没有强制要求Json,xml其实也可以尝试。并且附带HTTP状态码
POST返回的是新建的资源,
DELETE返回为空白,
Json返回的格式 ,GET返回的是一个或多个资源。
{
"id": 2,
"name": "果味",
"description": null,
"img": {
"url": "http://xxx.api.cn:81/images/xxxx.png"
}
}
PATCH 和PUT也是返回整个资源。
返回携带的HTTP状态码