《PHP精粹:编写高效PHP代码》——3.4节HTTP:超文本传输协议

简介:

本节书摘来自华章社区《PHP精粹:编写高效PHP代码》一书中的第3章,第3.4节HTTP:超文本传输协议,作者:(美)  Davey Shafik,更多章节内容可以访问云栖社区“华章社区”公众号查看

3.4 HTTP:超文本传输协议
HTTP(HyperText Transfer Protocol)是通过导线来传送Web请求和响应的数据传输格式。它包含了很多请求和响应的元数据,除了这些请求或响应的实体之外,我们也可以利用它来使用Web服务。我们也将看到其他的协议,例如XML-RPC和SOAP,它们也都是建立在HTTP基础上的。当我们在本章快结尾构建RESTful服务时,便可以广泛使用HTTP的功能了。
当我们开发一个简单的Web应用程序时,可能不会那么重视HTTP。但是如果你想了解缓存、不同文件类型的传递,特别是我们使用Web服务时如何使用其他的数据格式,那么以HTTP为基础的Web服务会让你受益匪浅。这些内容可能更偏重于理论性,但本节中我们会提供真实的示例并突出HTTP的特性,当你开发或调试任何使用HTTP的内容时,这些特性都会给你提供帮助,如果你忽略这些内容则风险自负。

3.4.1 HTTP信封
你见过一个原始的HTTP请求和响应吗?让我们分别通过请求和响应的示例来看看HTTP格式的组件。首先来看看请求。


dae4c4c977968ffc704fc7763a85086082bbdfec


a7529a66114c670849c6eb915365c47ebe22d211

让我们一行行地来看,第一行表明正在使用HTTP1.1版本,这个响应的状态是302 Found。这是一个状态码,302表示请求的内容在别处(很快我们会深入讲解状态码),Location文件头是这个请求的URL,Content-Type文件头告诉我们响应中包含什么格式的正文,与它配对的Content-Length文件头让我们知道,在这个响应的正文中可以找到什么并且如何解释正文。这里显示的还有Set-Cookie文件头,它发送Cookie来使用后面的请求,并且显示了请求发送的Date。最后,我们看到了正文内容,在本示例中就是用浏览器显示的HTML。
正如你所见,有大量“隐藏”内容包含在HTTP格式中,我们用它们增加客户端和服务器间交流的清晰度,其内容是关于我们正在请求的信息、要了解哪种格式等。当使用Web服务时候,可以使用文件头全面提高应用程序的健壮性和可预见性。
接下来我们来看看如何发送和调试HTTP请求,然后了解前面示例中曾提及的文件头的更多信息。

3.4.2 发送HTTP请求
在通常情况下,我们可以用不同的方法达到相同的目的。在本节中,我们来看看如何在命令行中使用cURL发送Web请求,以及在PHP中使用curl扩展和pecl_http发送Web请求。

  1. cURL
    上一个例子显示了一个名为cURL的程序的实际输出,它是用于请求URL的简单命令行工具。要请求一个URL,你只需输入:


ae800a10cb8ae89a0adbe65aaf4fcb2ec2f91a5f


7117821d68571497817e1e42be1b5a933c29218b

本示例中,我们再次使用相同的URL从bit.ly中得到短URL。我们用curl_init()初始化cURL句柄,然后再调用curl_setopt()。如果不设置CURLOPT_RETURNTRANSFER,curl_exec()将直接输出结果而不是返回结果!一旦cURL句柄被正确设置,我们就会调用curl_exec()立即发送请求。我们将响应的正文保存在$result中,因为正文是JSON格式,所以这个脚本对它进行解码然后再将其输出。
使用PHP cURL获取文件头
这个示例显示如何得到响应的正文,通常正文中的内容都是我们需要的。然而,如果你还需要文件头的信息,可以调用curl_info()函数,它会返回无数额外的信息。

  1. PHP pecl_http扩展
    这个模块并未默认包含在PHP中,但我们可以轻松通过PECL来安装它(更多内容见附录A)。该模块提供了一个更先进和更容易实现的接口来处理Web请求。如果你的应用程序需要运行很多普通的PHP安装程序,pecl_http并不是上策。但如果你要配置一个受你控制的平台,pecl_http绝对值得推荐。如下是一个使用pecl_http的例子。


ecc94d3a7b1acd7d2d81eeb25ef3ca539e4a9e74

这个简单请求的代码结构看起来类似于cURL扩展的代码结构;然而,若我们给这个请求添加很多更复杂的选项,例如发送和接收数据以及文件头信息,pecl_http扩展会更直观、更容易使用。pecl_http扩展提供程序和面向对象的两个接口,因此你可以选择最适合你或你的应用程序的接口。

  1. PHP流
    PHP可以在本地处理流。如果你在php.ini文件中启用allow_url_fopen选项,你可以这么做。


652f77834afd2b94b5b81ada2af2ee756fceabd0

这是抓取一个基本请求的简洁方式;然而,这种方式可以扩展,就像cURL和pecl_http扩展一样,我们用这种方式处理文件头和其他请求方法。要利用这一点,我们就必须使用$context参数,它接受一个有效的上下文。我们使用create_stream_context()函数创建上下文;这个文件细致清晰地显示如何设置主体内容、文件头以及处理流的方法。这种做法可能不太直观,但它的优势在于被大多数平台默认为直接使用,因此,当应用程序需要多个平台兼容时这是种不错的选择。

3.4.3 HTTP状态码
在前面的例子中,我们看到一个被cURL返回的文件头就是状态文件头,它的值为302 Found。每个HTTP响应都包含一个状态码,这个代码使我们得到一些初步印象,即这个请求是否成功,又或者出了什么问题。这个状态码总是3位数字,其中每个百位数表示这个响应不同的常规类型。表3.2给出了一个常见状态码的概要。


9bd438d1b6e5d9e00ee348e7b3a7f49349eb9c60

当我们使用API的时候,要养成检查响应状态码的习惯。
API中不正确的状态码
虽然本节讲述了使用状态码的正确理论,但是在现实世界中我们发现API根本无视这些理论,对于任何东西都返回200 OK,这是绝对正常的。这虽不是个好的做法;然而,当集成第三方API的时候你可能会接受这一点。

当我们阅读本章内容时,将看到如何发布我们自己的服务,尤其是RESTful服务如何包含合适的响应文件头和论述,如何为状态码选择一个有意义的值。

3.4.4 HTTP文件头
我们有大量可使用的HTTP文件头数组,并且根据请求和响应来区分它们。在本节中,我们将看到一些最常用的文件头以及它们所携带的信息,而且我们会看到如何从PHP应用程序中读取和写入文件头。当我们第一次介绍HTTP的时候已经在请求和响应中看到了文件头的示例,但是在PHP中如何管理它们呢?示例如下。


5526b36ea6bb525587de3f3e1e7e2c327fa25a32

在本章的示例中你将看到这样或类似的代码。我们可以通过超全局变量$_SERVER得到请求中的信息,包括accept文件头、host、path、GET参数等。我们仅仅使用header()函数就可以任意返回文件头到客户端。
PHP中的超全局
在PHP中你肯定很熟悉$_GET和$_POST变量,它们都是超全局(superglobal)的,这意味着它们被PHP变量初始化和填充后,可以在任何范围内使用。$_SERVER是另一个例子,它包含了关于请求的大量有用信息。

文件头必须首先发送给客户端;我们不能一开始就发送页面的正文,然后才意识到还需要发送文件头!然而,有时候我们的应用程序逻辑不使用这种方式,当我们意识到需要发送文件头时脚本已经发送一半了。比如,我们需要以某一方式通过脚本实现当一个用户没有登录时发送一个登录页面给他。我们可以使用如下语句重定向一个用户。

然而,如果你返回任何内容之后调用这个函数,你将看到一个错误。在理想状态下,我们希望确认在发送输出之前我们发送了所有的文件头,但是有时候这并不容易做到。但这未必都不可能,我们可以使用输出缓冲(output buffering)对内容排队并且先发送文件头。
在你的PHP脚本中可以使用ob_start()来启用输出缓冲,或用php.ini设置output_buffering为默认打开,启用输出缓冲会导致PHP开始存储你输出的脚本而不是立即将它们发送到客户端。当脚本结束或者你调用了ob_flush()函数,PHP才会将内容发送到客户端。
如果你打开了输出缓冲并开始发送输出,紧接着你会发送一个文件头,当缓冲区被清空的时候,文件头会在正文内容之前发送到客户端。这可以让我们避免代码输出先于文件头发送的问题。
我们粗略地论及一些常用的文件头,现在让我们认真地看看在应用程序中可能会用到的一些文件头,见表3.3。
这并不是一个很全面的清单,如果你想了解更多详细内容,在Wikipedia上有一个很详尽的列表。不过表3.3概括了我们经常使用的一些基本文件头,特别是在本节内容中也将用到它们。在Web服务中有两个我们经常遇到的文件头:Accept和Content-Type。


c0a6be156d17964496d230c478ef01fd065d776d

在这里我们看到了一系列被逗号分隔的值,其中一些还包含分号和一个q值,那么这些表明什么呢?实际上,一个没有q值的格式是首选格式,因此,如果一台服务器可以提供HTML或XHTML,那么它就应该选择没有q值的格式。如果没用这种格式,那就退而求其次选择其他可接受的格式。q值的默认值为1,因此我们降低要求,下一个最好的选择要求提供XML。如果服务器不能提供这几种格式,那么/表示服务器不管有什么样的格式都应该发送,而客户端接收结果后将尽可能地处理它们。
Accept文件头是请求文件头的一个组成部分,服务器接收它之后,计算出哪种格式应该返回,接着用Content-Type文件头发回响应。这个Content-Type文件头告诉客户端请求的正文是哪种格式。我们需要知道这些内容以便于更好地理解它们!除此以外,我们想知道是否解码JSON、解析XML或者显示HTML。Content-Type文件头非常简单,因此没有必要提供什么选择。

内容类型和错误
作为一个规则,我们应该始终用响应被预期的格式返回响应。这里有一个常见的错误:我们使用Web服务通常应该返回JSON的时候,却返回了HTML或一些其他格式。客户端可能无法解析这样的结果。因此我们应当始终确保以相同的格式返回,并正确设置所有响应的Content-Type文件头。

通常来说,这些文件头不一定都有良好支持或易于理解。然而,这是在Web上管理内容协商的最佳方式,因此我们推荐使用这种方法。

3.4.5 HTTP动词
当我们编写Web表单时,可以在GET方法和POST方法之间做一个选择。如下所示是一个基本的表单。


2c453352b00beaacc676e8cc9ab85e41997a1944

我们可以看到提交的表单数据和相应的Content-Type数组不在URL中,而在这个请求的正文中。
使用Web服务,我们将看到使用了各种各样的动词;当我们使用表单时,通常情况下都会使用GET方法和POST方法,而且你所知的提交数据方式仍然有效。在RESTful服务中有一些常用的动词,我们可以使用GET、POST、PUT以及DELETE来创建、检索、更新、删除数据。在本章后面有更多关于REST的内容。

相关文章
|
12月前
|
监控 测试技术 Go
告别传统Log追踪!GOAT如何用HTTP接口重塑代码监控
本文介绍了GOAT(Golang Application Tracing)工具的使用方法,通过一个Echo问答服务实例,详细展示了代码埋点与追踪技术的应用。内容涵盖初始化配置、自动埋点、手动调整埋点、数据监控及清理埋点等核心功能。GOAT适用于灰度发布、功能验证、性能分析、Bug排查和代码重构等场景,助力Go项目质量保障与平稳发布。工具以轻量高效的特点,为开发团队提供数据支持,优化决策流程。
752 89
|
10月前
|
安全 网络安全 流计算
修改代码以确保对SSL和HTTP异常的正确处理。
记得,在海上和代码世界里,风暴总是突如其来。但只要你的代码准备妥当,合理地处理SSL和HTTP异常,你的小船就能安全航行,最终到达它的目的地。
215 12
|
存储 缓存 搜索推荐
HTTP500代码怎么解决?常见的5xx网页错误及其原因
本文介绍了如何修复HTTP 500错误及常见的5xx网页错误。500错误表示服务器无法处理请求,可能由文件权限、脚本错误、数据库连接或配置问题引起。作为用户,可尝试重新加载页面、检查URL或清除缓存;作为网站所有者,需检查`.htaccess`文件、服务器日志、插件冲突及PHP版本等。此外,文章还列举了其他5xx错误(如502、503、504等)及其原因,帮助定位和解决服务器端问题,避免影响流量与搜索引擎排名。
9061 4
|
网络协议 网络安全 网络虚拟化
本文介绍了十个重要的网络技术术语,包括IP地址、子网掩码、域名系统(DNS)、防火墙、虚拟专用网络(VPN)、路由器、交换机、超文本传输协议(HTTP)、传输控制协议/网际协议(TCP/IP)和云计算
本文介绍了十个重要的网络技术术语,包括IP地址、子网掩码、域名系统(DNS)、防火墙、虚拟专用网络(VPN)、路由器、交换机、超文本传输协议(HTTP)、传输控制协议/网际协议(TCP/IP)和云计算。通过这些术语的详细解释,帮助读者更好地理解和应用网络技术,应对数字化时代的挑战和机遇。
1425 3
|
开发者
HTTP状态码是由网页服务器返回的三位数字响应代码,用于表示请求的处理结果和状态
HTTP状态码是由网页服务器返回的三位数字响应代码,用于表示请求的处理结果和状态
454 2
|
存储 算法 数据安全/隐私保护
基于 HTTP Header 传输签名参数
基于 HTTP Header 传输签名参数
378 13
|
存储 前端开发 NoSQL
拿下奇怪的前端报错(四):1比特丢失导致的音视频播放时长无限增长-浅析http分片传输核心和一个坑点
在一个使用MongoDB GridFS存储文件的项目中,音频和视频文件在大部分设备上播放时长显示为无限,而单独播放则正常。经调查发现,问题源于HTTP Range请求的处理不当,导致最后一个字节未被正确返回。通过调整请求参数,使JavaScript/MongoDB的操作范围与HTTP Range一致,最终解决了这一问题。此案例强调了对HTTP协议深入理解及跨系统集成时注意细节的重要性。
432 0
|
PHP
php 获取带http或https的域名
php 获取带http或https的域名
420 4
|
前端开发 安全 JavaScript
HTTP的系统登录页面,如何避免明文传输用户密码?
该文讨论了登录页面中密码安全传输的问题。当使用HTTP时,密码以明文形式传输,存在风险。在示例中,前端使用JavaScript的CryptoJS库和当前时间戳作为动态加密key对密码进行DES加密。后端接收到密文后,利用相同的时间戳解密。为了增强安全性,文章还建议使用RSA等非对称加密算法。
2401 7
|
网络协议 Python
Python实现HTTP 传输的断点续传机制
使用Python `requests`库实现HTTP断点续传下载大文件,通过设置`Range`头部从上次中断的位置开始继续下载。示例代码展示了一个名为`resume_download`的函数,它接收URL、文件名和最后字节位置参数,以追加方式打开文件并逐块写入内容。要启用HTTP长连接,可添加`Connection: keep-alive`到请求头。
1117 0
下一篇
开通oss服务