[TOC]

1、HTTP 介绍:

1.1 简介

​ HTTP协议是超文本传输协议,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。HTTP是一个基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)。

1.2 HTTP 工作原理

​ HTTP(超文本传输协议)是应用层协议。它是整个数据通信的基础,基于请求/响应模式,客户端与服务器之间通过互相发送报文来通信,工作流程如下:

  1. 建立连接: 客户端(通常是Web浏览器)和服务器之间首先需要建立一个TCP连接。这是因为HTTP协议通常承载于TCP协议之上,确保数据可靠传输
  2. 发送请求: 客户端向服务器发送一个HTTP请求,这个请求包含请求行、请求头和请求体。请求行包括请求方法(如GET或POST),所请求资源的URL以及HTTP协议版本。请求头包含附加信息,比如用户代理、Cookie等。如果是POST请求,请求体中还会包含提交的数据。
  3. 服务器响应: 服务器接收到请求后,根据请求内容和服务器上的资源生成HTTP响应。响应同样由三部分组成:状态行、响应头和响应体。状态行包括HTTP状态码和原因短语,响应头包含服务器类型、内容类型等附加信息,响应体则携带着实际返回给客户端的数据,例如HTML页面或图片等。
  4. 传输数据: 服务器将响应通过之前建立的TCP连接发送回客户端。客户端收到响应后,浏览器会根据返回的内容类型渲染出相应的页面或者处理其他类型的数据。
  5. 断开连接: 数据传输完成后,客户端和服务器关闭TCP连接并释放相关资源。由于HTTP是无状态的,每次通信都是独立的,不会默认保存之前的请求或响应信息。如果需要跟踪用户的状态,通常会使用Cookie或会话机制来实现。

1.3 常见的web服务器

  1. Apache HTTP Server:也被称为阿帕奇服务器,它是最广泛使用的Web服务器之一。作为一个开源项目,Apache可以运行在各种操作系统上,包括Unix、Windows和Linux。它以稳定性、可扩展性和安全性著称,在处理大量请求时表现出色。

  2. Nginx:Nginx是一个高性能的HTTP和反向代理服务器,它以处理高并发连接而闻名。Nginx消耗的资源较少,因此在负载较高的情况下仍能保持较低的内存和CPU使用率。

  3. Tomcat:虽然Apache Tomcat主要是作为Java 容器,但它也可以作为独立的Web服务器使用,尤其适合需要动态生成内容的Web应用。

    1561893004169

HTTPD和NGINX的区别

  1. 处理客户端请求Apache采用同步多进程模型,为每个请求创建一个新线程。这意味着在高并发场景下,Apache会为每个连接分配一个独立的进程或线程,这可能会导致资源使用量随着并发数的增加而线性增长。Nginx则采用异步非阻塞方式,使用事件驱动架构在一个线程中处理多个请求。这种模型使得Nginx在处理大量并发连接时更为高效,尤其是在静态内容服务和反向代理方面。

  2. 性能和稳定性:Nginx因其轻量级和高效的事件驱动架构,在性能上通常优于Apache。它特别适用于需要处理高并发请求的场景。而Apache在低至中等流量的环境中表现良好,其模块化设计和丰富的功能使得它在稳定性和模块化方面有一定的优势。

1.4 HTTP注意事项:

  1. 无连接性:HTTP通常是一种无连接协议,这意味着每次连接只处理一个请求。一旦服务器处理完客户端的请求并且客户端接收到响应,连接就会断开。这种机制有助于节省传输时间,但同时也意味着每次新的请求都需要建立新的连接。

  2. 无状态性:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快。

  3. 缓存控制:为了提高加载速度和减少带宽消耗,HTTP提供了缓存机制。

  4. 持久连接:虽然HTTP/1.1默认是持久连接(也称为HTTP Keep-Alive),但这需要Web服务器和客户端的支持。持久连接可以减少TCP连接的建立和关闭所带来的开销,提高传输效率。

1.5 HTTP 消息结构

HTTP是基于客户端/服务端(C/S)的架构模型,通过一个可靠的链接来交换信息,是一个无状态的请求/响应协议。

一个HTTP”客户端”是一个应用程序(Web浏览器或其他任何客户端),通过连接到服务器达到向服务器发送一个或多个HTTP的请求的目的。

一个HTTP”服务器”同样也是一个应用程序(通常是一个Web服务,如Nginx、Apache Web服务器),通过接收客户端的请求并向客户端发送HTTP响应数据。

HTTP使用统一资源标识符(Uniform Resource Identifiers, URI)来传输数据和建立连接。用来标识互联网上某一资源的地址,通常用于访问网页、文件、图片等。

  • 协议:例如,http://https://

    域名:例如,www.tabke.love

    路径:指向具体的资源,例如,/tanke/tanke.html

    查询参数(可选):用于传递附加信息,例如,?id=123&name=test

https://www.kengni.com:80/tanke.html?id=123&name=test

1.6 客户端请求消息

客户端发送一个HTTP请求到服务器的请求消息包括以下格式:请求行(request line)、请求头部(header)、空行和请求数据四个部分组成,下图给出了请求报文的一般格式。

(https://www.baidu.com/s?ie=UTF-8&wd=QQ%E9%9F%B3%E4%B9%90,此链接可看请求头的内容)

1561893148999

img

  • GET /wzt/favicon.ico HTTP/1.1:表示请求方法为GET,请求的资源路径为/wzt/favicon.ico,使用的HTTP协议版本为1.1。
  • Accept: image/avif,image/webp,image/apng,image/svg+xml,image/,/*;q=0.8:表示客户端接受的图像类型和质量。
  • Accept-Encoding: gzip, deflate:表示客户端接受的压缩格式。
  • Accept-Language: zh-CN,zh;q=0.9:表示客户端接受的语言和优先级。
  • Connection: keep-alive:表示客户端希望保持连接,以便进行后续请求。
  • Cookie: _ga_C569W2WCN6=GS1.1.1712754252.1.0.1712754252.0.0.0; …:表示客户端发送的Cookie信息,用于服务器识别用户。
  • Host: www.mobiletrain.org:表示请求的目标主机名为www.mobiletrain.org。
  • Referer: http://www.mobiletrain.org/?pinzhuanbdtg=biaoti:表示请求的来源页面URL。
  • User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36:表示客户端的浏览器信息和操作系统信息。

image-20240411151326745

这段响应信息是HTTP协议的一部分,它包含了服务器对客户端请求的响应。以下是各个字段的含义:

  • HTTP/1.1 200 OK:这是HTTP协议的版本和状态码,表示请求成功。
  • Server: nginx:服务器使用的是nginx。
  • Date: Wed, 10 Apr 2024 13:04:29 GMT:响应生成的时间。
  • Content-Type: image/x-icon:响应的内容类型是图像,具体格式为.ico。
  • ETag: “63478391-47e”:ETag是用于缓存控制的标识符。
  • Access-Control-Allow-Origin: *:允许任何来源访问该资源。
  • Accept-Ranges: bytes:服务器接受字节范围请求。
  • X-Cache-Lookup: Cache Miss:表示请求的资源未在缓存中找到。
  • Last-Modified: Thu, 13 Oct 2022 03:18:41 GMT:资源的最后修改时间。
  • Content-Length: 1150:响应内容的长度,单位为字节。
  • X-NWS-LOG-UUID: 3120119176189980775:这可能是一个自定义的头部字段,用于日志记录。
  • Connection: keep-alive:表示客户端和服务器之间的连接将保持活动状态,以便进行后续请求。

1.7 服务器响应消息

HTTP响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。

1561893177737

*实例 *

下面实例是一点典型的使用GET来传递数据的实例:

客户端请求:

1
2
3
4
5
Connected to www.testpm.cn (47.244.247.240) port 80 (#0)
> GET /hello.txt HTTP/1.1 # 请求方式与版本协议。
> User-Agent: curl/7.29.0 #用什么客户端访问
> Host: www.testpm.cn #主机名,域名。主机和端口号,
> Accept: */* #匹配什么文件类型,“*” 是通用匹配。匹配所有类型

服务端响应:

1
2
3
4
5
6
7
8
9
< HTTP/1.1 200 OK       #请求返回的状态码
< Server: nginx/1.16.0 #请求的服务和版本号
< Date: Thu, 04 Jul 2019 08:19:40 GMT
< Content-Type: text/plain #文本类型,有html,plain:普通文本
< Content-Length: 12
< Last-Modified: Thu, 04 Jul 2019 08:13:25 GMT
< Connection: keep-alive #是否支持长连接
< ETag: "5d1db525-c" #标识,每次访问如果与最开始的一样返回304否则校验不一致返回200
< Accept-Ranges: bytes

1.8 描述HTTP 的工作过程

HTTP协议的工作过程可以通过一个简单的例子来解释,例如,当你在浏览器中输入一个URL(例如:www.qf.com/test/index.html?name=qf&age=18)并按下回车键时,背后发生了什么?

  1. 浏览器首先会解析你输入的URL,确定你要访问的是哪个网站,以及具体的页面路径。在这个例子中,你要访问的网站是www.qf.com。
  2. 浏览器会向DNS服务器发送一个请求,要求解析www.qf.com的IP地址。DNS服务器会返回对应的IP地址。
  3. 浏览器会向这个IP地址发送一个HTTP GET请求。这个请求包含了一些信息,例如你的浏览器类型,你接受的语言等。
  4. 服务器收到这个HTTP请求后,会解析这个请求,确定你要获取的是哪个页面。然后,服务器会从硬盘中找到这个页面,然后返回一个HTTP响应。这个响应包含了页面的内容,以及一些元信息,例如页面的类型,编码方式等。
  5. 浏览器收到HTTP响应后,会解析这个响应,然后将页面的内容显示在浏览器中。

1.9 HTTP 请求方法

根据HTTP标准,HTTP请求可以使用多种请求方法。

HTTP1.0定义了三种请求方法: GET, POST 和 HEAD方法。

HTTP1.1新增了五种请求方法:OPTIONS, PUT, DELETE, TRACE 和 CONNECT 方法。

重点方法:

GET:用于向服务器请求获取某个资源。(获取一个index.html页面)

POST:用于向服务器提交数据,通常用于表单提交、文件上传等场景。(会产生新的数据)

PUT:用于向服务器更新或保存某个资源,通常用于上传文件、更新数据等场景。(覆盖/更新文件、图片等,不会产生新的数据)

DELETE:用于向服务器删除某个资源,通常用于删除文件、删除数据等场景。

1561896279402

GETPOST是HTTP协议中两种常见的请求方法,它们的工作细节如下:

GET请求是最常见的请求方法,通常用于获取资源。

​ GET请求的参数会附加在URL之后,通过问号(?)分隔,参数之间用&符号连接。例如,http://www.qf.com/index.html?name=John&age=22。这种方式的缺点是传输数据的大小有限制(因为浏览器对URL的长度有限制),并且不适合传输敏感信息(如密码),因为参数会直接暴露在URL中。

POST请求通常用于提交数据。

​ POST请求将参数放在HTTP请求的主体中(HTTP的请求主体(Request Body)是HTTP请求消息的一部分,用于在客户端向服务器发送请求时附带额外的数据。这些数据可以是文本、JSON、XML或其他格式,具体取决于请求的类型和客户端与服务器之间的约定。),而不是URL中。POST请求没有对传输数据的大小进行限制,而且可以传输任何类型的数据,包括二进制数据。因此,POST请求通常用于提交表单数据。

下面是一个GET请求和POST请求的例子:

GET请求示例:

1
2
3
4
GET /index.html?name=maoxiansheng&age=18 HTTP/1.1
Host: www.qf.com
User-Agent: Mozilla/5.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8

POST请求示例:

1
2
3
4
5
6
7
8
9
POST /api/users HTTP/1.1  
Host: www.qf
Content-Type: application/json
Content-Length: 45

{
"name": "qianfeng",
"email": "qianfeng@1000phone.com"
}

在GET请求示例中,参数name=John&age=22附加在URL之后。在POST请求示例中,参数"name": "qianfeng", "email": "qianfeng@1000phone.com"放在HTTP请求的主体中。

需要注意的是,虽然POST请求在传输大量或敏感数据时更安全,但无论是GET还是POST,都不能提供真正的安全性。为了保护数据的安全,应该使用HTTPS协议,它可以对传输的数据进行加密。

1.10 HTTP 状态码

当浏览者访问一个网页时,浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前,此网页所在的服务器会返回一个包含HTTP状态码的信息头(server header)用以响应浏览器的请求。

HTTP状态码的英文为HTTP Status Code

下面是常见的HTTP状态码:

  • 200 - 请求成功,表示成功处理了请求的状态代码。
  • 301 - 表示被请求的资源已永久移动到新的位置。当服务器返回301状态码时,它会告诉客户端(如浏览器)请求的资源已被永久移动到另一个URL,客户端在接收到301响应后,应该使用新的URL发起后续的请求。

    比如建设一个网站后,将网站的url变换了,重新申请一个域名,但是希望之前的用户访问之前url仍然可以访问到,就可以做一个重定向新的url下面。比如京东最早域名www.360buy.com名重定向到现在www.jd.com

  • 302 - 302状态码表示临时重定向。当服务器收到请求时,如果资源暂时不可用或已经移动到其他位置,服务器会返回一个HTTP 302状态码,客户端会自动发送一个新的请求到这个新的URL地址,以获取所需的资源。
  • 404- 表示客户端请求的资源在服务器上不存在或无法找到。当浏览器或客户端尝试访问一个网页或资源,但服务器无法找到与请求URL对应的文件或页面时,就会返回这个错误。

    HTTP 404错误可能由以下原因引起:

    1. URL错误:输入的URL可能有误,比如拼写错误、大小写错误、路径错误或者参数错误等。
    2. 页面被删除或移动:请求的页面可能已经被删除,或者移动到了其他位置,而URL没有相应地更新。
    3. 服务器配置问题:服务器的配置可能存在问题,导致无法正确解析URL或找到相应的资源。
    4. 资源不存在:请求的资源(如文件、图片等)可能从未在服务器上创建或已被删除。
  • 403 - 表示服务器理解了客户端的请求,但是拒绝执行此请求。这通常意味着客户端没有访问所请求资源的权限。HTTP 403错误可能由多种原因引起,包括:

    1. 权限不足:服务器可能要求客户端提供有效的身份验证凭据,以便确定其是否具有访问请求资源的权限。如果客户端没有提供正确的凭据或凭据无效,服务器将返回403状态码。
    2. IP地址限制:服务器可能根据IP地址对访问进行限制。如果客户端的IP地址被服务器列入黑名单或没有被列入白名单,服务器将返回403状态码。
    3. 文件权限设置:服务器上的文件或目录可能设置了访问权限,如果客户端没有足够的权限访问这些文件或目录,服务器将返回403状态码。
  • 503-错误表示服务不可用,这通常意味着服务器暂时无法处理请求。

    1. 服务器过载:当服务器接收到的请求过多,超过了其处理能力时,就可能导致服务器过载。这可能是由于服务器硬件性能不足、网络带宽不足或应用程序代码存在问题等原因引起的。
    2. 服务器维护:服务器可能需要定期进行维护和升级,以保持其稳定性和性能。在这种情况下,服务器可能会暂时关闭,以便进行必要的更新和修复。
    3. 错误的服务器配置:Web服务器或应用服务器配置错误也可能导致HTTP 503错误。这包括代理服务器的配置错误或应用程序池的错误配置等。
  • 504-也称为“网关超时”(Gateway Timeout)错误,通常发生在作为网关或代理的服务器没有从上游服务器(如另一个代理服务器或Web服务器)收到及时的响应时。这通常意味着代理服务器等待上游服务器的响应时间过长,超出了设定的等待时间阈值。

    1. 上游服务器过载:上游服务器可能由于处理过多的请求或资源不足而无法及时响应代理服务器的请求。
    2. 网络延迟或故障:代理服务器与上游服务器之间的网络连接可能存在问题,导致请求和响应的传输延迟或失败。
    3. 上游服务器配置错误:上游服务器的配置可能存在问题,导致它无法正确处理代理服务器的请求。

HTTP状态码分类

HTTP状态码由三个十进制数字组成,第一个十进制数字定义了状态码的类型,后两个数字没有分类的作用。HTTP状态码共分为5种类型:

  • 1xx(信息性状态码) : 这类状态码表示请求已被服务器接收,需要客户端继续操作。
  • 2xx(成功状态码) : 这类状态码表示服务器已成功处理了请求。
  • 3xx(重定向状态码) : 这类状态码表示需要客户端采取进一步的操作才能完成请求。例如,301 Moved Permanently表示被请求的资源已永久移动到新位置,302 Found表示请求的资源现在临时从不同的URI响应请求。
  • 4xx(客户端错误状态码) : 这类状态码表示客户端似乎发生了错误,妨碍了服务器的处理。
  • 5xx(服务器错误状态码) : 这类状态码表示服务器在尝试处理请求时发生了错误。

1561896413177

HTTP状态码列表:

状态码 状态码英文名称 中文描述
100 Continue 继续。客户端应继续其请求
101 Switching Protocols 切换协议。服务器根据客户端的请求切换协议。只能切换到更高级的协议,例如,切换到HTTP的新版本协议
200 OK 请求成功。一般用于GET与POST请求
201 Created 已创建。成功请求并创建了新的资源
202 Accepted 已接受。已经接受请求,但未处理完成
203 Non-Authoritative Information 非授权信息。请求成功。但返回的meta信息不在原始的服务器,而是一个副本
204 No Content 无内容。服务器成功处理,但未返回内容。在未更新网页的情况下,可确保浏览器继续显示当前文档
205 Reset Content 重置内容。服务器处理成功,用户终端(例如:浏览器)应重置文档视图。可通过此返回码清除浏览器的表单域
206 Partial Content 部分内容。服务器成功处理了部分GET请求
300 Multiple Choices 多种选择。请求的资源可包括多个位置,相应可返回一个资源特征与地址的列表用于用户终端(例如:浏览器)选择
301 Moved Permanently 永久移动。请求的资源已被永久的移动到新URI,返回信息会包括新的URI,浏览器会自动定向到新URI。今后任何新的请求都应使用新的URI代替
302 Found 临时移动。与301类似。但资源只是临时被移动。客户端应继续使用原有URI
303 See Other 查看其它地址。与301类似。使用GET和POST请求查看
304 Not Modified 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。客户端通常会缓存访问过的资源,通过提供一个头信息指出客户端希望只返回在指定日期之后修改的资源
305 Use Proxy 使用代理。所请求的资源必须通过代理访问
306 Unused 已经被废弃的HTTP状态码
307 Temporary Redirect 临时重定向。与302类似。使用GET请求重定向
400 Bad Request 客户端请求的语法错误,服务器无法理解
401 Unauthorized 请求要求用户的身份认证
402 Payment Required 保留,将来使用
403 Forbidden 服务器理解请求客户端的请求,但是拒绝执行此请求
404 Not Found 服务器无法根据客户端的请求找到资源(网页)。通过此代码,网站设计人员可设置”您所请求的资源无法找到”的个性页面
405 Method Not Allowed 客户端请求中的方法被禁止
406 Not Acceptable 服务器无法根据客户端请求的内容特性完成请求
407 Proxy Authentication Required 请求要求代理的身份认证,与401类似,但请求者应当使用代理进行授权
408 Request Time-out 服务器等待客户端发送的请求时间过长,超时
409 Conflict 服务器完成客户端的PUT请求是可能返回此代码,服务器处理请求时发生了冲突
410 Gone 客户端请求的资源已经不存在。410不同于404,如果资源以前有现在被永久删除了可使用410代码,网站设计人员可通过301代码指定资源的新位置
411 Length Required 服务器无法处理客户端发送的不带Content-Length的请求信息
412 Precondition Failed 客户端请求信息的先决条件错误
413 Request Entity Too Large 由于请求的实体过大,服务器无法处理,因此拒绝请求。为防止客户端的连续请求,服务器可能会关闭连接。如果只是服务器暂时无法处理,则会包含一个Retry-After的响应信息
414 Request-URI Too Large 请求的URI过长(URI通常为网址),服务器无法处理
415 Unsupported Media Type 服务器无法处理请求附带的媒体格式
416 Requested range not satisfiable 客户端请求的范围无效
417 Expectation Failed 服务器无法满足Expect的请求头信息
500 Internal Server Error 服务器内部错误,无法完成请求
501 Not Implemented 服务器不支持请求的功能,无法完成请求
502 Bad Gateway 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
503 Service Unavailable 由于超载或系统维护,服务器暂时的无法处理客户端的请求。延时的长度可包含在服务器的Retry-After头信息中
504 Gateway Time-out 充当网关或代理的服务器,未及时从远端服务器获取请求
505 HTTP Version not supported 服务器不支持请求的HTTP协议的版本,无法完成处理

2、Nginx 服务

2.1 Nginx 介绍

Nginx (engine x) 是一个高性能的 HTTP 和反向代理服务,也是一个IMAP/POP3/SMTP服务。因它的稳定性、丰富的功能集、示例配置文件和低系统资源的消耗而闻名。

Nginx是一款轻量级Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行。其特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服务器中表现较好。

在高连接并发的情况下,Nginx是Apache服务器不错的替代品。

创始人伊戈尔·赛索耶夫

1561897072438

2.2 为什么选择 Nginx

Nginx(engine x)是一个高性能的HTTP和反向代理web服务器,同时也提供了IMAP/POP3/SMTP服务。它最初由伊戈尔·赛索耶夫为俄罗斯访问量第二的Rambler.ru站点开发,自发布以来,因其稳定性、丰富的功能集、简单的配置文件和低系统资源消耗而广受好评。

Nginx的特点包括:

  1. 高性能:Nginx使用事件驱动模型,可以同时处理大量的并发连接,而且在高负载和大流量情况下仍然能够保持良好的性能。
  2. 轻量级:Nginx的代码量较少,占用的内存也较少,使其可以在资源受限的系统中运行,并且在高负载下也不易崩溃。
  3. 可扩展性:Nginx支持众多的第三方模块,可以根据需要进行自定义开发,实现更多的功能。
  4. 高度可靠性:Nginx是基于稳定的、成熟的事件驱动架构开发的,能够有效地避免因代码错误或第三方库问题导致的崩溃,从而保证了服务的高可靠性。
  5. 热部署:Nginx支持在不停止服务的情况下更新配置文件和软件升级,为用户提供了极大的便利。

在功能方面,Nginx具有:

  1. HTTP代理与反向代理:作为web服务器,Nginx最常用的功能之一是反向代理。它可以根据不同的正则匹配,采取不同的转发策略,并且能够对返回结果进行错误页跳转、异常判断等。如果被分发的服务器存在异常,Nginx可以将请求重新转发给另一台服务器。
  2. 负载均衡:Nginx提供了多种负载均衡策略,如轮询、加权轮询和ip hash等,以优化请求的分配和处理方式,从而平均分配后端服务器的负载,提高系统的可用性和可靠性。
  3. Web缓存:Nginx支持对不同的文件做不同的缓存处理。

2.3 IO多路复用

2.3.1 I/O multiplexing【多并发】

  • 第一种方法就是最传统的多线程并发模型 (每进来一个新的I/O流会分配一个新的进程管理。)

多进程并发模型是一种传统的服务器架构模式,它的核心思想是利用操作系统的多进程机制来实现并发处理多个客户端请求。在这种模型中,主进程负责监听客户端的连接请求,一旦接收到新的请求,主进程会通过fork()操作创建一个子进程(线程)来独立处理这个请求。这样,父进程可以继续回到监听状态,等待其他客户端的连接。每个子进程处理完一个请求后就会退出,释放资源。这种模型的优点是可以快速响应客户请求,尤其是在客户与服务器交互频繁的场景下。

然而,这种模型也存在一些缺点:

  • 资源消耗:进程是操作系统资源分配的基本单位,每个进程都需要占用一定的内存和CPU资源。在高并发环境下,如果创建大量进程,会导致服务器资源消耗过快,增加服务器负载。

1561897144109

  • 第二种方法就是I/O多路复用(单个线程,通过记录跟踪每个I/O流(sock)的状态,来同时管理多个I/O流 。)I/O multiplexing 这里面的 multiplexing 指的其实是在单个线程通过记录跟踪每一个Sock(I/O流)的状态来同时管理多个I/O流。发明它的原因,是尽量多的提高服务器的吞吐能力。I/O多路复用是一种高效处理多个I/O流的技术,它允许单个线程通过记录和跟踪每个流的状态来同时管理多个I/O流,而不是为每个流创建单独的线程。这样做可以提高服务器应用程序的性能,尤其是在需要处理成千上万并发连接的情况下。

在同一个线程里面, 通过拨开关的方式,来同时传输多个I/O流。这句话描述的是一种单线程中管理多个I/O流的方法,其中“拨开关”的比喻可能是指通过在多个I/O流之间切换来实现并发处理的方式。这里的“拨开关”可以理解为线程在多个I/O流之间快速切换,检查哪个流准备好进行读或写操作。当一个流准备好时,线程就与之交互(读取数据或发送数据),然后迅速切换到下一个流。这种快速的切换给人的感觉就像是在“拨动开关”,在一个流和另一个流之间来回切换

1561897166658

一个请求到来了,nginx使用epoll接收请求的过程是怎样的?

  1. 建立监听:Nginx通过epoll创建一个事件监听的集合,这个集合能够同时监控多个网络连接的文件描述符。
  2. 事件注册:对于每一个进入的连接,Nginx会将其文件描述符注册到epoll中,以便对这些连接进行事件监听。
  3. 事件检测:epoll机制允许Nginx高效地检测哪些注册的连接有活动(比如数据可读或可写),而不需要像传统的轮询那样检查每个连接。
  4. 事件处理:一旦某个连接上有数据到来,epoll通知Nginx,然后Nginx可以立即响应该连接,处理传入的数据,例如读取HTTP请求。
  5. 动态调整:epoll能够动态地添加或移除所监听的文件描述符,这使得Nginx在处理大量并发连接时非常灵活和高效。
  6. 资源优化:由于不是所有连接在任何时刻都是活跃的,epoll只关注那些真正有事件发生的连接,从而节省了系统资源,提高了性能。
  7. 非阻塞I/O:Nginx利用epoll实现非阻塞I/O操作,这意味着内核在没有数据可读时不会将进程置于等待状态,而是让其继续执行其他任务。

2.3.2 异步,非阻塞

1
[root@web01 ~]# ps -aux | grep nginx

img

1个master进程,2个work进程

master进程只负责监听用户的请求,但并不处理请求。work进程才处理请求。

​ 每进来一个request,会有一个worker进程去处理。但不是全程的处理,处理到什么程度呢?处理到可能发生阻塞的地方,比如向后端服务器转发request,并等待请求返回。那么,这个处理的worker不会这么一直等着,他会在发送完请求后,注册一个事件:“如果upstream返回了,告诉我一声,我再接着干”。于是他就休息去了。这就是异步。此时,如果再有request 进来,他就可以很快再按这种方式处理。这就是非阻塞IO多路复用。而一旦上游服务器返回了,就会触发这个事件,worker进程才会来接手,这个request才会接着往下走。这就是异步回调

3、Nginx安装部署和配置管理

3.1 Nginx部署-Yum安装方式

访问nginx的官方网站:http://www.nginx.org/

Nginx版本类型

  • Mainline version: 主线版,即开发版
  • Stable version:最新稳定版,生产环境上建议使用的版本
  • Legacy versions: 遗留的老版本的稳定版

img

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#>>> 编写nginx yum源文件(稳定版)
[root@nginx-server ~]# vim /etc/yum.repos.d/nginx.repo
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true

#>>> 缓存元数据
[root@nginx-server ~]# yum makecache fast

#>>> 安装nginx服务
[root@nginx-server ~]# yum install nginx -y
1
2
#>>> 查看nginx相关信息
[root@nginx-server ~]# nginx -V

img

1
2
3
#>>> 查看NGINX版本信息
[root@nginx-server ~]# nginx -v
nginx version: nginx/1.24.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#>>> 关闭安全策略
[root@nginx-server ~]# setenforce 0
[root@nginx-server ~]# sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config

#>>> 关闭防火墙
[root@nginx-server ~]# systemctl disable --now firewalld

#>>> 启动nginx并设置开机启动
[root@nginx-server ~]# systemctl enable --now nginx

#>>> 查看nginx启动状态
[root@nginx-server ~]# systemctl status nginx

#>>> 查看nginx进程
[root@nginx-server ~]# ps -aux | grep nginx

#>>> 查看nginx端口
[root@nginx-server ~]# ss -tunlp | grep -w 80

浏览器输入ip访问:

1561536791743

3.2 Nginx 编译安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#>>> 安装gcc
[root@nginx-server ~]# yum -y install gcc gcc-c++

#>>> 安装pcre软件包(使nginx支持http rewrite模块)
[root@nginx-server ~]# yum install -y pcre pcre-devel

#>>> 安装openssl-devel(使nginx支持ssl)
[root@nginx-server ~]# yum install -y openssl openssl-devel

#>>> 安装zlib
[root@nginx-server ~]# yum install -y zlib zlib-devel

#>>> 创建用户nginx
[root@nginx-server ~]# useradd -s /sbin/nologin nginx

#>>> 下载安装包
[root@nginx-server ~]# wget http://nginx.org/download/nginx-1.24.0.tar.gz

#>>> 解压安装包
[root@nginx-server ~]# tar xzf nginx-1.24.0.tar.gz -C /usr/local/ && cd /usr/local/nginx-1.24.0/

#>>> 预备编译,指定相关参数
[root@nginx-server nginx-1.24.0]# ./configure --prefix=/usr/local/nginx --group=nginx --user=nginx --sbin-path=/usr/local/nginx/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/tmp/nginx/client_body --http-proxy-temp-path=/tmp/nginx/proxy --http-fastcgi-temp-path=/tmp/nginx/fastcgi --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-pcre --with-http_realip_module --with-stream

#>>> 编译安装
[root@nginx-server nginx-1.24.0]# make && make install

自动化安装NGINX脚本(生产勿用,需要修改其中的相关配置信息)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#>>> NGINX自动化安装脚本
$ vim install_nginx.sh
#!/bin/bash
ck_ok () {
if [ $? -ne 0 ]
then
echo "error."
exit 1
fi
}

# 关闭防火墙及selinux
disable () {
systemctl disable --now firewalld &>/dev/null
setenforce 0
sed -i 's#SELINUX=enforcing#SELINUX=disabled#g' /etc/selinux/config
}

repos_bak () {
mkdir /etc/yum.repos.d/repo.bak
cp -r /etc/yum.repos.d/*.repo /etc/yum.repos.d/repo.bak/
ck_ok
}

# 更换国内源
install_repos () {
sed -e 's|^mirrorlist=|#mirrorlist=|g' \
-e 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos|g' \
-i.bak \
/etc/yum.repos.d/CentOS-*.repo
ck_ok
yum install -y epel-release
sed -e 's!^metalink=!#metalink=!g' \
-e 's!^#baseurl=!baseurl=!g' \
-e 's!https\?://download\.fedoraproject\.org/pub/epel!https://mirrors.tuna.tsinghua.edu.cn/epel!g' \
-e 's!https\?://download\.example/pub/epel!https://mirrors.tuna.tsinghua.edu.cn/epel!g' \
-i /etc/yum.repos.d/epel{,-testing}.repo
yum makecache fast
yum install -y gcc gcc-c++ pcre pcre-devel openssl openssl-devel zlib zlib-devel wget
ck_ok
}

disable

repos_bak

install_repos
# 创建nginx启动用户
useradd -s /sbin/nologin nginx

read -p "请输入您所要安装的NGINX版本:" tags
wget http://nginx.org/download/nginx-${tags}.tar.gz
ck_ok

tar xzf nginx-${tags}.tar.gz -C /usr/local/ && cd /usr/local/nginx-${tags}/
./configure --prefix=/usr/local/nginx --group=nginx --user=nginx --sbin-path=/usr/local/nginx/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/tmp/nginx/client_body --http-proxy-temp-path=/tmp/nginx/proxy --http-fastcgi-temp-path=/tmp/nginx/fastcgi --pid-path=/var/run/nginx.pid --lock-path=/var/lock/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_gzip_static_module --with-pcre --with-http_realip_module --with-stream
ck_ok
make && make install
echo "编译安装完成"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#>>> nginx systemd 启动脚本
$ cat > /lib/systemd/system/nginx.service <<EOF
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStart=/usr/local/nginx/sbin/nginx -c /etc/nginx/nginx.conf
ExecReload=/bin/sh -c "/bin/kill -s HUP \$(/bin/cat /var/run/nginx.pid)"
ExecStop=/bin/sh -c "/bin/kill -s TERM \$(/bin/cat /var/run/nginx.pid)"

[Install]
WantedBy=multi-user.target
EOF

$ systemctl unmask nginx.service
$ systemctl daemon-reload
$ systemctl enable nginx
$ systemctl start nginx

Nginx 编译参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 查看 nginx 安装的模块
[root@localhost ~]# /usr/local/nginx/sbin/nginx -V

# 模块参数具体功能
--with-cc-opt='-g -O2 -fPIE -fstack-protector //设置额外的参数将被添加到CFLAGS变量。(FreeBSD或者ubuntu使用)
--param=ssp-buffer-size=4 -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2'
--with-ld-opt='-Wl,-Bsymbolic-functions -fPIE -pie -Wl,-z,relro -Wl,-z,now'

--prefix=/usr/local/nginx //指向安装目录
--conf-path=/etc/nginx/nginx.conf //指定配置文件
--http-log-path=/var/log/nginx/access.log //指定访问日志
--error-log-path=/var/log/nginx/error.log //指定错误日志
--lock-path=/var/lock/nginx.lock //指定lock文件
--pid-path=/run/nginx.pid //指定pid文件

--http-client-body-temp-path=/var/lib/nginx/body //设定http客户端请求临时文件路径
--http-fastcgi-temp-path=/var/lib/nginx/fastcgi //设定http fastcgi临时文件路径
--http-proxy-temp-path=/var/lib/nginx/proxy //设定http代理临时文件路径
--http-scgi-temp-path=/var/lib/nginx/scgi //设定http scgi临时文件路径
--http-uwsgi-temp-path=/var/lib/nginx/uwsgi //设定http uwsgi临时文件路径

--with-debug //启用debug日志
--with-pcre-jit //编译PCRE包含“just-in-time compilation”
--with-ipv6 //启用ipv6支持
--with-http_ssl_module //启用ssl支持
--with-http_stub_status_module //获取nginx自上次启动以来的状态
--with-http_realip_module //允许从请求标头更改客户端的IP地址值,默认为关
--with-http_auth_request_module //实现基于一个子请求的结果的客户端授权。如果该子请求返回的2xx响应代码,所述接入是允许的。如果它返回401或403中,访问被拒绝与相应的错误代码。由子请求返回的任何其他响应代码被认为是一个错误。
--with-http_addition_module //作为一个输出过滤器,支持不完全缓冲,分部分响应请求
--with-http_dav_module //增加PUT,DELETE,MKCOL:创建集合,COPY和MOVE方法 默认关闭,需编译开启
--with-http_geoip_module //使用预编译的MaxMind数据库解析客户端IP地址,得到变量值
--with-http_gunzip_module //它为不支持“gzip”编码方法的客户端解压具有“Content-Encoding: gzip”头的响应。
--with-http_gzip_static_module //在线实时压缩输出数据流
--with-http_image_filter_module //传输JPEG/GIF/PNG 图片的一个过滤器)(默认为不启用。gd库要用到)
--with-http_spdy_module //SPDY可以缩短网页的加载时间
--with-http_sub_module //允许用一些其他文本替换nginx响应中的一些文本
--with-http_xslt_module //过滤转换XML请求
--with-mail //启用POP3/IMAP4/SMTP代理模块支持
--with-mail_ssl_module //启用ngx_mail_ssl_module支持启用外部模块支持

3.3 NGINX配置文件详解

  1. 全局模块
1
2
3
4
5
6
7
8
#user  nobody;
worker_processes 1;

#error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;

#pid logs/nginx.pid;
  • user nobody;:指定 Nginx 进程运行的用户。
  • worker_processes 1;:指定 Nginx 启动的工作进程数。通常设置为 CPU 核心数。
  • error_log logs/error.log;:指定错误日志文件的路径和日志级别。
  • pid logs/nginx.pid;:指定存储 Nginx 主进程 PID 的文件路径。
  1. events模块
1
2
3
events {
worker_connections 1024;
}
  • worker_connections 1024;:每个工作进程允许的最大连接数。设置为 1024。该参数用于设置每个worker进程允许的最大并发连接数。worker_connections参数用于指定每个Nginx worker进程可以同时处理的最大连接数。在这个例子中,worker_connections
  • 设置为1024,表示每个worker进程最多可以同时处理1024个连接。通过设置worker_connections,可以限制每个worker进程的负载,避免因过多的并发连接导致服务器资源耗尽或性能下降。
  1. HTTP模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
http {
include mime.types;
default_type application/octet-stream;

#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';

#access_log logs/access.log main;

sendfile on;
#tcp_nopush on;

#keepalive_timeout 0;
keepalive_timeout 65;

#gzip on;
  • include mime.types;:包含 MIME 类型映射文件,告诉 Nginx 如何处理不同类型的文件。
  • default_type application/octet-stream;:默认的 MIME 类型,如果没有其他匹配的类型,使用这个。
  • log_formataccess_log:指定日志格式和访问日志路径。
  • sendfile on;:启用 sendfile 选项,提高文件传输效率。允许在内核级别直接将文件数据从磁盘传输到网络,而不需要通过用户空间的缓冲区。这样可以减少CPU和内存的开销,提高文件传输的效率。通过将sendfile设置为on,可以启用sendfile选项,从而优化文件传输的性能。这对于大文件传输或者需要快速响应的场景非常有用。
  • tcp_nopush on;:提高网络传输效率。允许在发送HTTP响应时控制数据包的发送方式。当TCP_NOPUSH选项被设置为on时,Nginx会在发送HTTP响应头之后立即发送响应体的数据,而不是等待整个响应体都准备好后再一起发送。这样可以减少延迟,提高传输效率。
  • keepalive_timeout 65;:保持连接超时时间,设置为 65 秒。允许在一个TCP连接上发送多个HTTP请求和响应,而不需要每次都重新建立连接。通过使用keepalive,可以减少TCP连接的建立和关闭次数,从而提高服务器的性能和效率。
  • gzip on;:启用 gzip 压缩。Gzip 压缩可以显著提高网站性能,通过减少传输数据的大小,加快网页加载速度。
  1. server模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
server {
listen 80;
server_name localhost;

#charset koi8-r;

#access_log logs/host.access.log main;

location / {
root html;
index index.html index.htm;
}

#error_page 404 /404.html;

error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}

# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}
  • listen 80;:指定虚拟主机监听的端口,设置为 80(HTTP)。
  • server_name localhost;:指定虚拟主机名称。
  • charset koi8-r;:设置字符集。
  • access_log logs/host.access.log main;:指定访问日志路径和格式。
  1. location 模块
1
2
3
4
location / {
root html;
index index.html index.htm;
}
  • location /:匹配根路径。
  • root html;:指定根目录路径为 html 目录。
  • index index.html index.htm;:指定默认的索引文件。
  1. 错误页面配置
1
2
3
4
error_page   500 502 503 504  /50x.html;
location = /50x.html {
root html;
}
  • error_page 500 502 503 504 /50x.html;:指定在发生 500、502、503、504 错误时,显示 /50x.html 页面。
  • location = /50x.html:精确匹配 /50x.html,并指定根目录为 html
  1. 代理和 FastCGI 配置

    FastCGI 是一种改进的CGI协议,通过优化性能和资源利用率,使得Web服务器能够更有效地处理动态内容的生成和处理,特别是在高流量和高并发的网络环境中表现出色。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
#location ~ \.php$ {
# root html;
# fastcgi_pass 127.0.0.1:9000;
# fastcgi_index index.php;
# fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
# include fastcgi_params;
#}
  • location ~ \.php$:使用正则表达式匹配以 .php 结尾的请求。
  • proxy_pass http://127.0.0.1;:将匹配到的请求代理到本地端口 80 上。
  • location ~ \.php$:使用正则表达式匹配以 .php 结尾的请求。
  • root html;:设置根目录为 html。表示根目录在 html 文件夹中。
  • fastcgi_pass 127.0.0.1:9000;:将匹配到的请求传递给本地运行的 FastCGI 服务器,该服务器监听在 127.0.0.1 的端口 9000 上。
  • fastcgi_index index.php;:使用 index.php 作为索引文件。
  • fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;:设置 SCRIPT_FILENAME FastCGI 参数,该参数指定了请求的 PHP 脚本文件的路径。$fastcgi_script_name 是请求的 URI,/scripts 是在服务器根目录中的路径。
  • include fastcgi_params;:包含 FastCGI 参数文件,该文件定义了一组 FastCGI 参数,通常存储在 Nginx 安装目录的 confconf.d 目录中。

当 Nginx 收到一个以 .php 结尾的请求时,这个请求将被传递给本地的 FastCGI 服务器进行处理。FastCGI 服务器通常是 PHP-FPM(PHP FastCGI Process Manager),它负责处理 PHP 脚本。Nginx 在这里充当一个 FastCGI 客户端,将请求转发给 FastCGI 服务器,然后将服务器的响应返回给客户端。

  1. 拒绝访问 .ht 文件
1
2
3
4
5
6
# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
  • location ~ /\.ht:匹配 .ht 文件。
  • deny all;:拒绝所有访问。被注释掉了。
  1. HTTPS 服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# HTTPS server
#
#server {
# listen 443 ssl;
# server_name localhost;

# ssl_certificate cert.pem;
# ssl_certificate_key cert.key;

# ssl_session_cache shared:SSL:1m;
# ssl_session_timeout 5m;

# ssl_ciphers HIGH:!aNULL:!MD5;
# ssl_prefer_server_ciphers on;

# location / {
# root html;
# index index.html index.htm;
# }
#}
  • listen 443 ssl;:指定服务器监听 443 端口,这是标准的 HTTPS 端口,并启用 SSL 功能。

  • server_name localhost;:指定服务器名称,这里设置为 localhost

  • ssl_certificate cert.pem;:指定服务器的 SSL 证书文件路径。cert.pem 是证书文件。

  • ssl_certificate_key cert.key;:指定服务器的 SSL 证书私钥文件路径。cert.key 是私钥文件。

  • ssl_session_cache shared:SSL:1m;:启用共享的 SSL 会话缓存,大小为 1MB。这有助于提高 SSL 握手的性能,因为客户端可以重用现有的 SSL 会话。

  • ssl_session_timeout 5m;:设置 SSL 会话超时时间为 5 分钟。

  • ssl_ciphers HIGH:!aNULL:!MD5;:指定允许使用的 SSL 加密套件。HIGH 表示高安全性套件,!aNULL 排除不带认证的套件,!MD5 排除使用 MD5 算法的套件。

  • ssl_prefer_server_ciphers on;:指示服务器优先使用自己的加密套件,而不是客户端的套件顺序。这有助于确保使用强加密。

Nginx配置文件组成部分

  • 全局块:这是配置文件的最顶层,用于定义对整个Nginx服务器生效的参数。例如,可以设置工作进程数、错误日志的位置等。全局块中配置的指令作用于整个Nginx服务器,而不是某个特定的server或location。
  • events块:位于全局块下面,用来设置与连接处理相关的参数,比如每个工作进程允许的最大并发连接数等。这个块通常用来调整Nginx如何处理网络连接和请求的传输速率。
  • http块:包含了所有与HTTP服务相关的设置,如路由匹配、静态文件服务、反向代理和负载均衡等。在http块内部,可以包含http全局块、多个server块以及每个server块中的多个location块。每个server块代表一个虚拟主机的配置,而location块则用于匹配并处理特定的URL请求。

检测nginx配置文件是否正确

1
2
[root@localhost ~]# ln -s /usr/local/nginx/sbin/nginx  /sbin/
[root@localhost ~]# nginx -t

通过 nginx 命令控制 nginx 服务

a、常用命令

1
2
3
4
5
6
nginx -c /path/nginx.conf  	     # 以特定目录下的配置文件启动nginx:
nginx -s reload # 修改配置后重新加载生效
nginx -s stop # 快速停止nginx
nginx # 快速启动nginx
nginx -t # 测试当前配置文件是否正确
nginx -t -c /path/to/nginx.conf # 测试特定的nginx配置文件是否正确

3.4 Nginx 日志文件详解

​ nginx 日志文件分为 log_formataccess_log 两部分

​ log_format 定义记录的格式,其语法格式为

​ log_format 样式名称 样式详情

​ 配置文件中默认有

1
2
3
log_format  main  'remote_addr - remote_user [time_local] "request" '
'status body_bytes_sent "$http_referer" '
'"http_user_agent" "http_x_forwarded_for"';
  1. log_format
  • log_format:定义日志格式。
  • main:这是日志格式的名称。在 access_log 指令中引用这个日志格式。
  1. remote_addr
  • $remote_addr:记录客户端的 IP 地址。这个字段表示请求是从哪个 IP 地址发出的。
  1. remote_user
  • $remote_user:记录客户端通过 HTTP 基本认证的用户名。如果请求没有进行认证,则这个字段为空。
  1. time_local
  • $time_local:记录请求的本地时间和日期。格式通常为 day/month/year:hour:minute:second timezone(例如:03/Jul/2024:08:33:00 +0800)。
  1. request
  • $request:记录请求行,包含了请求方法、请求 URI 和 HTTP 协议版本。例如:GET /index.html HTTP/1.1
  1. status
  • $status:记录响应的 HTTP 状态码。
  1. body_bytes_sent
  • $body_bytes_sent:记录发送给客户端的响应主体的字节数,不包括响应头。如果响应没有主体,则这个字段为 0
  1. $http_referer
  • $http_referer:记录请求的 Referer 头部字段的值。这个字段表示客户端从哪个页面链接到当前请求的页面。
  1. http_user_agent
  • $http_user_agent:记录请求的 User-Agent 头部字段的值。这个字段包含了客户端浏览器的详细信息。
  1. http_x_forwarded_for
  • $http_x_forwarded_for:记录请求的 X-Forwarded-For 头部字段的值。这个字段通常由代理服务器添加,表示原始客户端的 IP 地址。

日志示例如下:

img

3.5 使用 limit_rate 限制客户端传输数据的速度

​ 限制客户端的下载速度。这个功能对于控制带宽、优化服务器性能以及防止带宽滥用。

在这个例子中,limit_rate设置为50k,表示每个客户端连接的最大传输速率为50KB/s。通过设置limit_rate,可以控制客户端请求的传输速率,避免因单个客户端占用过多带宽而导致其他客户端无法正常访问。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#>>> 修改nginx配置文件
[root@localhost ~]# vim /etc/nginx/conf.d/limit_rate.conf
server {
listen 80;
server_name limit.tanke.love;
location / {
root /www/limit;
index index.html index.htm;
limit_rate 50k; #对每个连接的限速为2k/s
# limit_rate_after 1m; # 下载 1 MB 后开始限速
}
}

#>>> 上传测试视频
[root@localhost ~]# ll /www/limit/
总用量 156180
-rw-r--r--. 1 root root 159920333 8月 1 22:22 1.mp4

#>>> 准备默认资源文件
[root@localhost ~]# echo "limit_rate" > /www/limit/index.html

#>>> 检查语法格式
[root@localhost ~]# nginx -t

#>>> 重新加载配置文件
[root@localhost ~]# systemctl reload nginx

#>>> 测试限流
[root@localhost ~]# curl http://192.168.174.20/1.mp4 -o /dev/null

img

  • % Total: 文件的总大小。

    % Received: 已接收的百分比。

    % Xferd: 已传输的数据量。

    Average Speed: 平均下载速度。

    Time Total: 总时间。

    Time Spent: 已经花费的时间。

    Time Left: 剩余时间。

    Current Speed: 当前下载速度。

Current Speed 显示为 52668 bytes/sec(约为 51.43359375 KB/sec),接近设置的 50k 限制。ZZ

3.6 Nginx 虚拟主机配置

什么是虚拟主机?
虚拟主机是一种特殊的软硬件技术,它可以将网络上的每一台计算机分成多个虚拟主机,每个虚拟主机可以独立对外提供web服务,这样就可以实现一台主机对外提供多个web服务,每个虚拟主机之间是独立的,互不影响。

1561605672295

Nginx 支持三种类型的虚拟主机配置,具体包括基于域名、基于IP和基于端口的虚拟主机

  1. 基于域名的虚拟主机:这种类型的虚拟主机使用server_name指令来区分不同的虚拟主机,适用于外部网站的发布。通过域名系统(DNS)解析到同一个IP地址的不同域名可以指向不同的网站内容。
  2. 基于IP的虚拟主机:一块主机绑定多个IP地址,每个IP地址对应一个虚拟主机。这种方式要求服务器有多个IP地址,每个虚拟主机通过不同的IP进行访问。
  3. 基于端口的虚拟主机:通过不同的端口号来区分不同的虚拟主机,适用于需要在同一台物理服务器上运行多个服务的情况。

Nginx通过提供虚拟主机的功能,允许用户在单一服务器上部署多个网站或应用,而无需安装多个Nginx实例。

1. 基于域名的虚拟主机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#>>> 修改配置文件
[root@localhost ~]# vim /etc/nginx/conf.d/limit_rate.conf
server {
listen 80;
server_name limit.tanke.love;
location / {
root /www/limit/;
index index.html index.htm;
limit_rate 2k;
}
}

server {
listen 80;
server_name one.tanke.love;
location / {
root /www/one;
index index.html index.htm;
}
}

#>>> 创建资源目录和文件
[root@localhost ~]# mkdir /www/one
[root@localhost ~]# echo "one" > /www/one/index.html

#>>> 检测nginx配置文件语法
[root@localhost ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful

#>>> 热加载nginx
[root@localhost ~]# systemctl reload nginx

注意:如果修改的是nginx的资源文件,则不需要进行服务重启和热更新。

2. 基于ip的虚拟主机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
[root@localhost ~]# ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN qlen 1
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
link/ether 00:0c:29:17:f1:af brd ff:ff:ff:ff:ff:ff
inet 192.168.174.20/24 brd 10.0.105.255 scope global dynamic ens33
valid_lft 81438sec preferred_lft 81438sec
inet6 fe80::9d26:f3f0:db9c:c9be/64 scope link
valid_lft forever preferred_lft forever
[root@localhost ~]# ifconfig ens33:1 192.168.174.21/24
[root@localhost ~]# ifconfig
ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.174.20 netmask 255.255.255.0 broadcast 10.0.105.255
inet6 fe80::9d26:f3f0:db9c:c9be prefixlen 64 scopeid 0x20<link>
ether 00:0c:29:17:f1:af txqueuelen 1000 (Ethernet)
RX packets 9844 bytes 1052722 (1.0 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 5567 bytes 886269 (865.4 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

ens33:1: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 192.168.174.21 netmask 255.255.255.0 broadcast 10.0.105.255
ether 00:0c:29:17:f1:af txqueuelen 1000 (Ethernet)

2、配置通过ip区分的虚拟机
[root@localhost ~]# vim /etc/nginx/conf.d/ip_server.conf
server {
listen 80;
server_name 192.168.174.20;
location / {
root /www/20;
index index.html index.htm;
}
}

server {
listen 80;
server_name 192.168.174.21;
location / {
root /www/21;
index index.html index.htm;
}
}

# 创建站点目录和资源文件
[root@localhost ~]# mkdir /www/{20,21}
[root@localhost ~]# echo "20" > /www/20/index.html
[root@localhost ~]# echo "21" > /www/21/index.html

# 检测nginx配置文件语法
[root@localhost ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# 热加载nginx
[root@localhost ~]# systemctl reload nginx

# 访问
http://192.168.174.20
http://192.168.174.21
# 补充
-- 删除绑定的临时ip
[root@localhost ~]# ifconfig ens33:1 192.168.174.21 down
重启一下nginx
[root@localhost ~]# systemctl restart nginx

3. 基于端口的虚拟主机

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@localhost ~]# vim /etc/nginx/conf.d/port_server.conf
server {
listen 80;
server_name port.tanke.love;
location / {
root /www/port80/;
index index.html index.htm;
}
}

server {
listen 81;
server_name port.tanke.love;
location / {
root /www/port81;
index index.html index.htm;
}
}

# 创建站点目录和资源文件
[root@localhost ~]# mkdir /www/{port80,port81}
[root@localhost ~]# echo "port80" > /www/port80/index.html
[root@localhost ~]# echo "port81" > /www/port81/index.html

# 重新加载配置文件:
[root@localhost ~]# nginx -t
[root@localhost ~]# systemctl reload nginx
测试访问:
浏览器输入:http://port.tanke.love
浏览器输入:http://port.tanke.love:81

4、Nginx proxy 代理

4.1 反向代理产生背景

反向代理产生的背景是互联网的高速发展和用户需求的激增

  • 提高服务器性能:随着用户数量的增加,单个服务器处理大量请求的能力有限,通过使用反向代理,可以将请求分散到多个服务器上,从而提高整体的处理能力和效率。
  • 负载均衡:反向代理可以作为负载均衡器,将客户端的请求均匀地分配到后端的相同服务器群中,确保每个服务器的负载处于合理水平,避免某单一服务器过载而影响服务质量。
  • 安全性提升:反向代理可以隐藏后端服务器的真实IP地址,增加系统的安全性。保护内部网络不受外界直接访问。
  • 缓存静态内容:反向代理服务器可以缓存静态内容,如图片、CSS和JavaScript文件,这样可以减少对后端服务器的重复请求,加快内容的加载速度。

4.2 反向代理服务的实现

  1. 配置反向代理服务器:首先需要设置一个反向代理服务器,可以是Nginx、Apache等常见的Web服务器软件。在服务器上进行相应的配置,指定后端服务器的地址和端口号。
  2. 安装和配置后端服务器:根据具体需求,选择并安装适当的后端服务器软件,如Tomcat、Node.js等。然后对后端服务器进行配置。
  3. 配置反向代理规则:在反向代理服务器上配置转发规则,将客户端的请求转发到正确的后端服务器。这可以通过修改配置文件或使用特定的命令来实现。

    1561616855038

1561616834649

4.3 正向代理和反向代理的区别

  1. 代理对象不同正向代理的代理对象是客户端,它位于客户端和目标服务器之间,客户端通过代理服务器发送请求到目标服务器,并从目标服务器获取内容。反向代理的代理对象是服务器,它位于客户端和目标服务器之间,客户端的请求直接发送到反向代理服务器,然后由反向代理服务器将请求转发给目标服务器。
  2. 使用场景不同:正向代理通常用于访问被限制或不可访问的内容,或者在内部网络中提供对外访问的方式。反向代理则主要用于实现负载均衡、安全策略、缓存等功能,提高网站性能和可用性。
  3. 设置需求不同:正向代理通常需要客户端进行设置,以使其通过代理服务器进行访问,这通常涉及到在客户端的网络设置中指定代理服务器的IP地址和端口号。反向代理则通常不需要客户端进行任何设置,客户端发出的请求直接发送到反向代理服务器,然后由反向代理服务器转发请求到后端真实服务器。
  4. 安全性不同:正向代理隐藏客户端的IP地址和身份信息,因为请求是通过代理服务器发出的。反向代理隐藏服务器的真实IP地址和身份信息,客户无需知道后端服务的真实地址。因为请求是直接发送到反向代理服务器,然后由反向代理服务器将请求转发给目标服务器。

1561616889383

1561617154985

反向代理中,proxyserver同属一个LAN,反向代理中代理的对象是服务端,proxy和server同属一个LAN,对client透明。

1561617180382

正向代理和反向代理对比示意图,正向代理中代理的对象是客户端,proxy和client同属一个LAN,对server透明;

1561618001304

4.4 常用的集群软件

  • 开源:LVS,Keepalived,Haproxy,Nginx
  • 商业:F5

4.5 Nginx proxy模块配置

4.5.1 Nginx proxy代理模块

1
ngx_http_proxy_module

4.5.2 代理配置

​ 准备两台nginx主机,一台为代理服务器,一台为后端服务器。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#>>> nginx 01代理服务器配置修改
[root@localhost ~]# vim /etc/nginx/conf.d/pass_server.conf
server {
listen 80;
server_name limit.tanke.love;
location / {
proxy_pass http://192.168.174.21:80;
proxy_redirect default;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_connect_timeout 30;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_buffering on;
proxy_buffer_size 32k;
proxy_buffers 4 128k;
proxy_busy_buffers_size 256k;
proxy_max_temp_file_size 256k;

}
}

# 参数解释
proxy_pass http://192.168.174.21:80; # 代理的真实后端地址;

proxy_set_header # proxy_set_header指令来设置代理服务器向后端服务器发送的请求头部信息。在这个例子中,proxy_set_header Host $http_host;表示将客户端请求的Host头部信息(即$http_host变量)设置为代理服务器向后端服务器发送的请求头部信息中的Host字段。

proxy_set_header X-Real-IP $remote_addr; # 使用proxy_set_header指令来设置代理服务器向后端服务器发送的请求头部信息。在这个例子中,proxy_set_header X-Real-IP $remote_addr;表示将客户端的IP地址(即$remote_addr变量)设置为代理服务器向后端服务器发送的请求头部信息中的X-Real-IP字段。

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # 将客户端的IP地址和代理服务器的IP地址一起传递给后端服务器。

proxy_connect_timeout 30; # proxy_connect_timeout指令来设置代理服务器与后端服务器建立连接的超时时间。

proxy_send_timeout 60; # proxy_send_timeout指令来设置代理服务器向后端服务器发送请求的超时时间。

proxy_read_timeout 60; # proxy_read_timeout指令来设置代理服务器从后端服务器接收响应的超时时间。

proxy_buffering on; # proxy_buffering on;表示开启代理服务器的缓冲功能。目的是为了让代理服务器能够缓存从后端服务器接收到的响应数据,从而提高整体的性能和用户体验。通过开启代理服务器的缓冲功能,可以确保代理服务器能够将响应数据缓存起来,从而减少与后端服务器之间的通信次数,提高响应速度。

proxy_buffer_size 32k; # proxy_buffer_size指令来设置代理服务器缓冲区的大小。

proxy_buffers 4 128k; # 代理服务器的缓冲区数量和每个缓冲区的大小。这个参数决定了Nginx在代理客户端请求时用于缓存后端服务器响应的缓冲区的总数量和每个缓冲区的最大容量。4:这是缓冲区的数量,即Nginx将创建4个缓冲区来存储来自后端服务器的响应数据。128k:这是每个缓冲区的大小,即每个缓冲区可以存储最多128KB的数据。

proxy_busy_buffers_size 256k; # 设置代理服务器的繁忙缓冲区大小。这个参数决定了Nginx在处理高负载时,用于缓存后端服务器响应的额外缓冲区的大小。

proxy_max_temp_file_size 256k; # 设置代理服务器的最大临时文件大小。

注意事项: buffer 缓冲区

  • 并发连接数:更多的并发连接意味着需要更多的繁忙缓冲区。每个连接可能会使用一个繁忙缓冲区,因此需要根据预期的并发量来设置繁忙缓冲区的数量。
  • 响应大小:如果后端服务器返回的响应体通常较大,可能需要增加繁忙缓冲区的大小以避免性能问题。同时,如果响应体很小,那么过多的繁忙缓冲区或过大的繁忙缓冲区可能会浪费内存。
  • 内存限制:Nginx的繁忙缓冲区大小不能无限制地增加,因为服务器的内存是有限的。必须确保繁忙缓冲区的配置不会消耗过多的内存,影响其他进程或服务的性能。
  • 后端服务器性能:后端服务器的响应速度也会影响繁忙缓冲区大小的设置。如果后端服务器响应迅速,可能不需要很大的繁忙缓冲区;如果响应慢,较大的繁忙缓冲区可以减少Nginx等待数据的时间。

4.5.3 服务端配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost ~]# cat /etc/nginx/conf.d/default.conf 
server {
listen 80;
server_name localhost;

location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

4.5.4 测试访问

1
2
# 访问代理服务器域名
游览器访问:limit.tanke.love

服务端查看/var/log/nginx/access.log 访问日志

image-20240328111901587

192.168.174.20 反向代理服务器地址
192.168.174.21 客户端真实地址


5、Nginx 负载均衡

5.1 负载均衡作用

  1. 提高并发处理能力:通过将网络流量平均分发到多个服务器上,负载均衡器能够提高系统整体的响应速度和并发处理能力。
  2. 增强系统的伸缩性:当需要增加或减少服务器数量时,负载均衡器可以重新分配请求,确保系统可以根据需求进行扩展或缩减。
  3. 提升系统的可用性:负载均衡器会监控各个服务器的状态,自动跳过不可用的服务器,确保请求只被分发给可用的服务器,从而保证服务的连续性。
  4. 安全防护功能:一些负载均衡解决方案提供了安全功能,如黑白名单处理、防火墙以及防御DDoS攻击等。
  5. 优化资源使用:负载均衡技术可以确保没有单个服务器承受过多的负载,从而避免过载,实现资源的最优使用。
  6. 最小化响应时间:通过智能地将请求分配给多个服务器,负载均衡有助于减少用户的等待时间,提供更快的服务响应。

5.2 Nginx 负载均衡模块

1
2
ngx_http_upstream_module
ngx_http_proxy_module
  • ngx_http_upstream_module:用于定义负载均衡策略和后端服务器组的模块。upstream指令用于定义后端服务器组,这些服务器组会被Nginx用来进行负载均衡。
  • ngx_http_proxy_module:负责将客户端的请求转发到upstream模块定义的后端服务器组。通过proxy_pass指令,Nginx可以将请求发送到指定的服务器组,从而实现负载均衡。

5.3 Nginx upstream 配置

​ upstream 配置与http块下,和server块同级。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#>>> 代理服务器配置
[root@localhost ~]# vim /etc/nginx/nginx.conf

http {
upstream test {
server 192.168.174.21:80;
server 192.168.174.22:80;
}
...
}

[root@localhost ~]# vim /etc/nginx/conf.d/upstream_server.conf
server {
listen 80;
server_name upstream.tanke.love;
location / {
proxy_pass http://test;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
...
}

# 后端主机nginx02配置网页资源
[root@localhost ~]# echo "nginx02" > /usr/share/nginx/html/index.html
[root@localhost ~]# cat /usr/share/nginx/html/index.html
nginx02

# 后端主机nginx03配置网页资源
[root@localhost ~]# echo "nginx03" > /usr/share/nginx/html/index.html
[root@localhost ~]# cat /usr/share/nginx/html/index.html
nginx03

# 代理服务器检查配置文件语法
[root@localhost ~]# nginx -t

# 代理服务器热加载nginx
[root@localhost ~]# systemctl reload nginx


# 访问代理服务器
http://upstream.tanke.love

5.3.1 Nginx负载均衡策略

  • 轮询(Round Robin):这是默认的负载均衡策略。在这种策略下,每个请求会按时间顺序逐一分配到不同的后端服务器节点,确保每个节点平均处理请求。

    • 优点
      • 简单高效:轮询策略实现起来相对简单,不需要复杂的算法支持,因此在处理请求时效率较高。
      • 自动故障转移:如果某个后端服务器宕机或无法响应,Nginx能够自动检测到并将请求转发到其他健康的服务器上,这样可以提高系统的整体可用性。
      • 均匀分配:在大多数情况下,轮询策略能够保证请求被均匀地分配到各个后端服务器上,从而提高了系统的吞吐量和资源的利用率。
    • 缺点
      • 会话一致性问题:由于请求可能会被随机分配到不同的服务器上,这可能会导致同一个用户的连续请求落在不同服务器上,从而影响会话的一致性。
      • 缺乏灵活性:轮询策略不会考虑后端服务器的实际处理能力,也不会根据请求的内容进行优化分配,这可能会导致某些服务器过载而其他服务器却处于空闲状态。
  • 加权轮询(Weighted Round Robin):这种策略允许根据服务器的性能为其分配权重,性能更好的服务器可以处理更多的请求。

    • 优点
      • 性能优化:允许性能更强的服务器处理更多的请求,这样可以充分利用资源,提高整体的处理能力。
      • 灵活性:可以根据实际情况调整服务器的权重,以适应不同的负载需求和服务器性能。
      • 适应性:在服务器性能差异较大时,能够更好地平衡负载,避免某些服务器过载而其他服务器空闲的情况发生。
    • 缺点
      • 压力集中:在系统启动初期,高权重的节点可能会承受较大的压力,导致机器负载突然增高,而其他机器则处于低负载状态,这可能会影响服务的平滑性。
      • 复杂性:相比简单的轮询策略,加权轮询需要更多的配置和管理,增加了系统的复杂性。
      • 会话一致性:尽管加权轮询考虑了服务器的性能,但仍然可能导致同一用户的请求被分配到不同服务器,影响会话一致性。
  • 最少连接(Least Connections):在这个策略下,Nginx会将新请求分配给当前连接数最少的服务器,这样可以保证服务器间的负载更加均衡。

    • 优点
      • 提高服务器利用率:在高负载情况下,将请求转发给当前连接数较少的后端服务器,可以更有效地利用服务器资源,避免某些服务器过载。
      • 适应性强:适用于处理时间不确定或服务器性能差异较大的环境,能够根据实际情况动态调整请求分配,提高整体的处理能力和效率。
      • 减少响应时间:通过将请求分配给当前连接数较少的服务器,可以减少用户的等待时间,提高服务的响应速度。
    • 缺点
      • 可能导致空闲:在某些情况下,如果某个服务器的处理能力非常强,可能会导致其他服务器长期处于空闲状态,从而影响其性能和稳定性。
      • 可能不公平:如果服务器的处理能力不同,仅仅根据连接数来分配请求可能会导致某些服务器承担更多的负载,而其他服务器则相对较少,这在一定程度上违背了负载均衡的公平性原则。
  • IP Hash:这种策略会根据客户端IP地址的哈希值来选择服务器,这样可以确保同一用户的请求总是被发送到同一台服务器,有助于实现会话保持。

    • 优点
      • 会话保持:根据客户端IP的哈希值来分配请求,确保来自同一IP的请求被发送到相同的后端服务器。这有助于维持客户端与服务器之间的会话状态,特别是对于需要保持登录状态或其他会话信息的应用来说非常重要。
      • 减少响应时间:由于同一用户的请求被定向到同一台服务器,可以减少因服务器间会话恢复而产生的延迟,提高应用的响应速度。
    • 缺点
      • 无法处理高并发:当某个客户端的请求量异常增加时,可能会导致该客户端对应的后端服务器负载过高,而其他服务器却处于相对空闲的状态。
  • URL Hash:这种策略会根据请求的URL的哈希值来选择服务器,适用于需要根据URL分配请求到特定服务器的场景。

    • 优点

      • 会话保持:确保相同URL的请求始终被分配到同一台后端服务器,有助于保持会话的一致性,特别适用于需要维护用户登录状态等场景。
      • 提高效率:由于相同URL的请求被定向到同一服务器,这可以减少服务器间状态复制的需要,提高缓存效率,尤其适用于后端服务器使用缓存的场景。

      缺点

      • 服务器动态变化敏感:如果后端服务器列表发生变化(如增加或减少服务器),可能会导致哈希结果的变化,进而影响到之前已经分配的服务器,这需要在使用中特别注意。
  • Fair:根据后端服务器的响应时间进行动态分配请求,实现更合理的负载均衡。nginx本身不支持fair,需要独立安装upstream_fair模块。

    • 优点
      • 动态调整:Fair策略能够动态地根据服务器的实际处理能力来分配请求,这样可以更合理地利用服务器资源,提高整体的处理效率。
      • 适应性强:对于那些处理能力不一或处理时间不确定的服务器集群,Fair策略能够更好地平衡负载,避免某些服务器过载而其他服务器空闲的情况发生。
    • 缺点
      • 对突发流量敏感:由于Fair策略是根据服务器当前的响应时间来分配请求,因此对于突发流量的处理可能不够迅速,需要一段时间来调整分配策略。
      • 可能引起资源分配不均:在服务器性能差异较大的情况下,Fair策略可能会导致性能较好的服务器承担更多的请求,而性能较差的服务器则可能处于较为空闲的状态。
轮询策略
1
2
3
4
  upstream test {
server 192.168.174.21:80;
server 192.168.174.22:80;
}
  • 负载均衡状态配置参数:

    • down; 表示不在将用户的请求转发到此主机中;

    • backup; 预留的备份机器。当其他所有的非backup机器出现故障时,才会请求backup机器,因此这台机器的压力最轻。

    • max_fails:表示允许的最大失败次数。当一个后端服务器在 fail_timeout 时间内连续失败这么多次后,Nginx 会将该服务器标记为不可用,不再向其转发请求。默认值为 1。

    • fail_timeout:表示失败检查的时间间隔。在这个时间段内,如果一个后端服务器的失败次数达到了 max_fails,那么 Nginx 会将其标记为不可用。默认值为 10s。

    • # down
      http {
          upstream backend {
              server 192.168.174.21 down;
              server 192.168.174.22;
          }
          ...
      }
      
      # backup;
      http {
          upstream backend {
              server 192.168.174.21 backup;
              server 192.168.174.22;
          }
          ...
      }
      
      # max_fails  fail_timeout
      http {
          upstream backend {
              server 192.168.174.21 max_fails=3 fail_timeout=30s;
              server 192.168.174.22 max_fails=3 fail_timeout=30s;
          }
          ...
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11

      ##### **加权轮询**

      ```bash
      http {
      upstream backend {
      server 192.168.174.21 weight=2;
      server 192.168.174.22 weight=1;
      }
      ...
      }
ip_hash
1
2
3
4
5
6
7
8
http {
upstream backend {
ip_hash;
server 192.168.174.21;
server 192.168.174.22;
}
...
}
URL Hash
1
2
3
4
5
6
7
8
http {
upstream backend {
hash $request_uri;
server 192.168.174.21;
server 192.168.174.22;
}
...
}
最少连接
1
2
3
4
5
6
7
8
http {
upstream backend{
least_conn;
server 192.168.174.21;
server 192.168.174.22;
}
...
}
fair
1
2
3
4
5
6
7
8
http {
upstream backend {
fair;
server 192.168.174.21;
server 192.168.174.21;
}
...
}

参考链接:https://github.com/gnosek/nginx-upstream-fair

6、Nginx会话保持

6.1 什么是会话保持

会话保持是一种在负载均衡环境中维持客户端和服务器之间的交互状态的机制

会话保持的目的是确保来自同一用户的连续请求被分配到同一台服务器上处理,从而保持用户会话的连续性。这对于维护用户登录状态等敏感信息至关重要。以下是一些关键点:

  1. 识别关联性:会话保持可以识别客户端与服务器之间交互过程的关联性。
  2. Web开发技术:在Web开发中,会话保持通常通过Session和Cookie机制来实现。
  3. Session与Cookie:Session是一种服务器端的会话管理机制,而Cookie是客户端的一种缓存机制,两者都可以用于跟踪用户会话。
  4. 粘滞会话(Sticky Sessions):会话保持有时也称为粘滞会话,它确保一系列相关联的访问请求会被分配到同一台服务器上处理。

6.2 什么是Cookie和Session

Cookie和Session都是用于跟踪和管理网站用户状态的技术,但它们的存储位置和使用方式有所不同

Cookie 是一种存储在用户浏览器中的小型文本文件,它可以用来记录用户信息,如登录状态、网站偏好设置等。当用户访问一个网站时,服务器会向用户的浏览器发送Cookie,浏览器会保存这些信息。下次用户再次访问该网站时,浏览器会将这些Cookie信息发送回服务器,服务器通过这些信息来识别用户并生成个性化的内容。

Session 则是在服务器端记录用户信息的一种机制。当用户访问服务器时,服务器会创建一个新的Session,并将其唯一标识(如ID)存储在Cookie中,然后发送给客户端浏览器。这样,每次用户与服务器交互时,服务器都可以通过这个Session标识来识别用户,并获取与之相关的信息,如登录状态或购物车内容等。

6.3 Nginx实现回话保持的手段

  1. 基于客户端IP地址的会话保持
  • ip_hash:这种方法使用源地址哈希算法,确保来自同一客户端的请求总是被发送到相同的后端服务器。这有助于保持客户端与服务器之间的会话状态,特别是对于需要维持登录状态或其他会话信息的应用来说非常重要。然而,这种方法的缺点是如果后端服务器宕机,会话信息可能会丢失,同时如果多个客户端处于同一局域网内,可能会导致负载不均衡。

    1
    2
    3
    4
    5
    6
    7
    8
    http {
    upstream backend {
    ip_hash;
    server 192.168.174.21;
    server 192.168.174.22;
    }
    ...
    }
  1. 基于后端存储的会话保持:(了解)
  • 可以通过数据库、Redis或Memcached等后端存储服务来实现Session的复制和同步。这种方法不依赖于Nginx本身,而是通过后端存储服务的会话同步机制来保持用户会话状态。

我们知道一个请求在经过一个服务器处理时,服务器会保存相关的会话信息,比如session,但是该请求如果第一个服务器没处理完,通过nginx轮询到第二个服务器上,那么这个服务器是没有会话信息的。

最典型的一个例子:用户第一次进入一个系统是需要进行登录身份验证的,首先将请求跳转到Tomcat1服务器进行处理,登录信息是保存在Tomcat1 上的,这时候需要进行别的操作,那么可能会将请求轮询到第二个Tomcat2上,那么由于Tomcat2 没有保存会话信息,会以为该用户没有登录,然后继续登录一次,如果有多个服务器,每次第一次访问都要进行登录,这显然是很影响用户体验的。

这里产生的一个问题也就是集群环境下的 session 共享,如何解决这个问题?

  • 选择一个中间件,将登录信息保存在一个中间件上,这个中间件可以为Redis这样的数据库。那么第一次登录,我们将session 信息保存在 Redis 中,跳转到第二个服务器时,我们可以先去Redis上查询是否有登录信息,如果有,就能直接进行登录之后的操作了,而不用进行重复登录。

7、Nginx动静分离

7.1 介绍

Nginx 动静分离是指将动态和静态资源请求分开处理,以提高网站性能和稳定性

Nginx作为一个高性能的Web服务器,可以有效地处理静态资源,如HTML、JavaScript、CSS和图片等文件,而将动态资源请求,通常是指需要后端服务器处理的请求,如PHP、Java等,交给专门的应用服务器处理,如Tomcat。

  • 提高响应速度:Nginx对静态资源的处理非常高效,可以快速响应客户端的请求,减少页面加载时间。
  • 减轻后端压力:动态资源请求通常涉及到数据库操作,将这些请求交给专门的应用服务器处理,可以避免Nginx承担过多的计算任务,从而保证动态内容的生成和处理更加专注和高效。
  • 提升网站稳定性:动静分离可以有效分散服务器负载,避免单点故障,提高整个网站的稳定性和可靠性。
  • 优化资源利用:通过合理配置Nginx,可以实现客户端缓存,减少不必要的数据传输,节省带宽。

img

7.2 环境准备

1
2
3
192.168.174.20 # 反向代理服务器
192.168.174.21 # 处理静态资源服务器
192.168.174.22 # 处理动态请求服务器

7.2.1 代理服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#>>> 修改配置文件
[root@localhost ~]# vim /etc/nginx/conf.d/upstream.conf
upstream static {
server 192.168.174.21:80;
}
upstream phpserver {
server 192.168.174.22:80;
}
server {
listen 80;
server_name localhost;
#动态资源加载
location ~ \.(php|jsp)$ {
proxy_pass http://phpserver;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
#静态资源加载
location ~* .*\.(html|gif|jpg|png|bmp|swf|css|js)$ {
proxy_pass http://static;
proxy_set_header Host $host:$server_port;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}

#>>> 检查语法格式
[root@localhost ~]# nginx -t

#>>> 重新加载配置文件
[root@localhost ~]# systemctl reload nginx

7.2.2 静态资源服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#>>> 修改配置文件
[root@localhost ~]# vim /etc/nginx/conf.d/static.conf
server {
listen 80;
server_name localhost;

location ~* \.(html|jpg|png|js|css|gif|bmp|jpeg)$ {
root /home/www/nginx;
index index.html index.htm;
}
}

#>>> 检查语法格式
[root@localhost ~]# nginx -t

#>>> 重新加载配置文件
[root@localhost ~]# systemctl reload nginx

#>>> 创建站点目录
[root@localhost ~]# mkdir -p /home/www/nginx

#>>> 创建站点文件
[root@localhost ~]# echo "jingtai" > /home/www/nginx/index.html //模拟静态资源

7.2.3 动态资源服务器配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#>>> 安装 PHP 所需的epel源
[root@localhost ~]# rpm -Uvh https://mirror.webtatic.com/yum/el7/epel-release.rpm

#>>> 安装 PHP 安装源
[root@localhost ~]# rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm

#>>> 安装PHP
[root@localhost ~]# yum install php71w-xsl php71w php71w-ldap php71w-cli php71w-common php71w-devel php71w-gd php71w-pdo php71w-mysql php71w-mbstring php71w-bcmath php71w-mcrypt php71w-fpm -y

#>>> 启动PHP服务
[root@localhost ~]# systemctl enable --now php-fpm #不启动的话会报502错误

#>>> 备份 nginx 配置文件
[root@localhost ~]# cp /etc/nginx/conf.d/default.conf /etc/nginx/conf.d/default.conf.old

#>>> 修改配置
[root@localhost ~]# vim /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name localhost;
location ~* \.php$ {
root /home/nginx/html; # 指定网站目录
fastcgi_pass 127.0.0.1:9000; # 指定访问地址
fastcgi_index index.php; # 指定默认文件
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; # 站点根目录,取决于root配置项
include fastcgi_params; # 包含nginx常量定义
}
}

#>>> 检查语法
[root@localhost ~]# nginx -t

#>>> 重新加载配置文件
[root@localhost ~]# systemctl reload nginx

#>>> 创建站点目录
[root@localhost ~]# mdkir -p /home/nginx/html

#>>> 创建站点文件
[root@localhost ~]# echo "dongtai" > /home/nginx/html/index.php //模拟动态资源

8、Nginx防盗链

7.1 介绍

​ Nginx可以通过配置实现防盗链,以保护网站资源不被未经授权的使用。两个网站 A 和 B, B网站引用了A网站上的图片,这种行为就叫做盗链。 防盗链,就是要防止B引用A的图片。以下是一些常用的方法:

使用refer模块:这是Nginx中一个用于检查HTTP请求头中的Referer字段的模块。通过配置valid_referers指令,可以指定允许访问资源的合法来源域名或URL模式。如果请求的Referer头部与这些模式匹配,则认为请求是合法的,否则拒绝访问。这种方法相对简单,但可能受到伪造Referer头的影响。

Nginx防盗链模块

1
ngx_http_referer_module

如何区分哪些是不正常的用户?

HTTP Referer是Header的一部分,当浏览器向Web服务器发送请求的时候,一般会带上Referer,告诉服务器我是从哪个页面链接过来的,服务器借此可以获得一些信息用于处理,例如防止未经允许的网站盗链图片、文件等。因此HTTP Referer头信息是可以通过程序来伪装生成的,所以通过Referer信息防盗链并非100%可靠,但是,它能够限制大部分的盗链情况。

7.2 Nginx防盗链配置

环境准备:

1
2
3
192.168.174.20 #受害者(被盗链者)
192.168.174.21 #违法者(盗链者)
192.168.174.22 #旁观者(客户端)

简单了解Nginx默认access日志格式

image-20240328212852810

1
2
3
4
5
6
7
8
9
10
192.168.174.1	# 客户端地址
-
- # 访问用户
[28/Mar/2024:21:28:07 +0800] # 访问时间
"GET / HTTP/1.1" # 请求方法,请求路径,协议版本
200 # 状态码
7806 # 访问字节大小
"-" # 是否从其他链接跳转,链接地址
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36" # 客户端访问方式
"-" # 反向代理地址

image-20240328213256174

上图红色方框中,显示上一级链接地址。如果存在则显示,无则显示"-"

受害者环境准备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
192.168.174.20 #受害者(被盗链者)
[root@localhost ~]# vim /etc/nginx/conf.d/referers_nginx.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index qf.png;
}
}

[root@localhost ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@localhost ~]# systemctl reload nginx

浏览器访问http://192.168.174.20

image-20240328213615308

非法者环境准备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
192.168.174.21 #违法者(盗链者)

[root@localhost ~]# vim /etc/nginx/conf.d/referers_nginx.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html;
}
}

[root@localhost ~]# vim /usr/share/nginx/html/index.html
<html>
<head>
<meta charset="utf-8">
<title>qf.com</title>
</head>
<body style="background-color:red;">
<img src="http://192.168.174.20/qf.png"/>
</body>
</html>

[root@localhost ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@localhost ~]# systemctl reload nginx

游览器访问http://192.168.174.21
image-20240328214339171

查看被盗链主机的访问日志

image-20240328214448292

http://192.168.174.21/" 盗链者地址

禁用盗链IP/URL,受盗链主机配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
[root@nginx-server ~]# vim /etc/nginx/nginx.conf
# 日志格式添加"$http_referer"
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# valid_referers 使用方式
Syntax: valid_referers none | blocked | server_names | string ...;
Default: —
Context: server, location

# none : 允许没有http_referer的请求访问资源;
# blocked : 允许不是http://开头的,不带协议的请求访问资源;
# server_names : 只允许指定ip/域名来的请求访问资源(白名单)。


[root@localhost ~]# vim /etc/nginx/conf.d/referers_nginx.conf
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index qf.png;
valid_referers none blocked www.jd.com; # 允许www.jd.com 允许访问
if ($invalid_referer) {
return 403;
}
}
}
# none允许空值访问,客户端直接访问。所以加不加ip都可以访问,如果把none擦除,就不能访问了
valid_referers none blocked www.jd.com 192.168.174.21; 添加到白名单盗链者就可以继续访问到图片。

[root@localhost ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@localhost ~]# systemctl reload nginx

盗链者再次访问图片
image-20240328220321210

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
在其中一台机器测试:
测试不带http_refer:
[root@localhost ~]# curl -I "http://192.168.174.20"
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Thu, 28 Mar 2024 14:08:14 GMT
Content-Type: image/png
Content-Length: 7806
Last-Modified: Thu, 28 Mar 2024 13:24:12 GMT
Connection: keep-alive
ETag: "66056f7c-1e7e"
Accept-Ranges: bytes


测试带非法http_refer:
[root@localhost ~]# curl -e http://www.baidu.com -I "http://192.168.174.20"
HTTP/1.1 403 Forbidden
Server: nginx/1.24.0
Date: Thu, 28 Mar 2024 14:08:30 GMT
Content-Type: text/html
Content-Length: 153
Connection: keep-alive


测试带合法的http_refer:
[root@localhost ~]# curl -e http://www.jd.com -I "http://192.168.174.20"
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Thu, 28 Mar 2024 14:09:17 GMT
Content-Type: image/png
Content-Length: 7806
Last-Modified: Thu, 28 Mar 2024 13:24:12 GMT
Connection: keep-alive
ETag: "66056f7c-1e7e"
Accept-Ranges: bytes


[root@localhost ~]# curl -e http://192.168.174.22 -I "http://192.168.174.20"
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Thu, 28 Mar 2024 14:09:34 GMT
Content-Type: image/png
Content-Length: 7806
Last-Modified: Thu, 28 Mar 2024 13:24:12 GMT
Connection: keep-alive
ETag: "66056f7c-1e7e"
Accept-Ranges: bytes

image-20240328221027750

9、Nginx重定向

9.1 Nginx rewrite介绍

Rewrite对称URL Rewrite,即URL重写,就是把传入Web的请求重定向到其他URL的过程。

9.2 Rewrite 相关指令

  • return指令:用于返回指定的HTTP状态码,通常与重定向一起使用,例如return 301 $uri会将请求重定向到新的URI。
  • if语句:允许根据某些条件执行特定的重写规则。这个指令可以让你根据不同的请求头或请求参数来应用不同的重写规则。
  • set指令:用于设置变量,这些变量可以在rewrite规则中被引用,或者在其他地方用于进一步的处理。
  • rewrite指令:这是实现URL重写的关键指令,它根据正则表达式部分的内容,将请求重定向到替换(replacement)部分,结尾是标志(flag)。

9.2.1 if语句

应用环境

1
server块,location块

语法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
if (condition) { … }
if 可以支持如下条件判断匹配符号
~ 正则匹配 (区分大小写)
~* 正则匹配 (不区分大小写)
!~ 正则不匹配 (区分大小写)
!~* 正则不匹配 (不区分大小写)
-f 和!-f 用来判断是否存在文件
-d 和!-d 用来判断是否存在目录
-e 和!-e 用来判断是否存在文件或目录
-x 和!-x 用来判断文件是否可执行

在匹配过程中可以引用一些Nginx的全局变量
$args 请求中的参数;
$document_root 针对当前请求的根路径设置值;
$host 请求信息中的"Host",如果请求中没有Host行,则等于设置的服务器名;
$limit_rate 对连接速率的限制;
$request_method 请求的方法,比如"GET""POST"等;
$remote_addr 客户端地址;
$remote_port 客户端端口号;
$remote_user 客户端用户名,认证用;
$request_filename 当前请求的文件路径名(带网站的主目录/usr/local/nginx/html/images /a.jpg)
$request_uri 当前请求的文件路径名(不带网站的主目录/images/a.jpg)
$query_string$args相同;
$scheme 用的协议,比如http或者是https
$server_protocol 请求的协议版本,"HTTP/1.0""HTTP/1.1";
$server_addr 服务器地址,如果没有用listen指明服务器地址,使用这个变量将发起一次系统调用以取得地址(造成资源浪费);
$server_name 请求到达的服务器名;
$document_uri$uri一样,URI地址;
$server_port 请求到达的服务器端口号;

9.2.2 Rewrite flag标记位

Nginx的rewrite指令支持多种flag,用于控制重写规则的行为。以下是一些常用的flag:

  1. last:表示完成当前的重写规则后,停止处理后续的重写规则,从头再匹配。
  2. break:表示完全停止处理后续的重写规则。
  3. redirect:表示将请求重定向到新的URI,并返回HTTP状态码为302。
  4. permanent:表示将请求永久重定向到新的URI,并返回HTTP状态码为301。

这些flag可以根据需要组合使用,以实现不同的URL重写和重定向行为。例如,rewrite ^/old-url/(.*)$ /new-url/$1 permanent;中的permanent flag表示将请求永久重定向到新的URI,并返回HTTP状态码为301。

last和break区别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
[root@localhost ~]# vim /etc/nginx/conf.d/last_break.conf
server {
listen 80;
server_name localhost;

location / {
root /usr/share/nginx/html;
index index.html index.htm;
}

location /break/ {
root /usr/share/nginx/html;
rewrite .* /test/break.html break;
}

location /last/ {
root /usr/share/nginx/html;
rewrite .* /test/last.html last;
}

location /test/ {
root /usr/share/nginx/html;
rewrite .* /test/test.html break;
}
}
[root@localhost conf.d]# cd /usr/share/nginx/html/
[root@localhost html]# mkdir test
[root@localhost html]# echo "last" > test/last.html
[root@localhost html]# echo "break" > test/break.html
[root@localhost html]# echo "test" > test/test.html
  • last 标记在本条 rewrite 规则执行完后,会对其所在的 server { … } 标签重新发起请求;

  • break 标记则在本条规则匹配完成后,停止匹配,不再做后续的匹配;

redirect 和 permanent区别

则是返回的不同方式的重定向,对于客户端来说一般状态下是没有区别的。而对于搜索引擎,相对来说301的重定向更加友好,如果我们把一个地址采用301跳转方式跳转的话,搜索引擎会把老地址的相关信息带到新地址,同时在搜索引擎索引库中彻底废弃掉原先的老地址。使用302重定向时,搜索引擎(特别是google)有时会查看跳转前后哪个网址更直观,然后决定显示哪个,如果它觉的跳转前的URL更好的话,也许地址栏不会更改。

9.2.3 Rewrite 常见案例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
192.168.174.20 rewrite.tanke.love
# 举例一:
[root@localhost ~]# vim /etc/nginx/conf.d/rewrite_server.conf
server {
listen 80;
server_name rewrite.tanke.love;
location /a {
root /html;
index index.html index.htm;
rewrite .* /b/index.html permanent;
}

location /b {
root /html;
index index.html index.htm;
}
}
# 创建网站资源路径
[root@localhost ~]# mkdir -p /html/{a,b}
[root@localhost ~]# echo "a" > /html/a/index.html
[root@localhost ~]# echo "b" > /html/b/index.html
# 检查配置文件语法是否错误,热加载nginx
[root@localhost ~]# nginx -t
[root@localhost ~]# systemctl reload nginx

# 游览器访问http://rewrite.tanke.love/a

上述案例使用游览器访问http://rewrite.tanke.love/a后会永久重定向至http://rewrite.tanke.love/b/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
192.168.174.20 rewrite.tanke.love
# 举例二:
[root@localhost ~]# vim /etc/nginx/conf.d/rewrite02_server.conf
server {
listen 80;
server_name rewrite.tanke.love;

location /2023/a {
root /var/www/html;
index index.html;
rewrite ^/2023/(.*)$ /2024/$1 permanent;
}

location /2024/a {
root /var/www/html;
index index.html;
}
}

# 准备网站资源目录
[root@localhost ~]# mkdir -p /var/www/html/{2023,2024}/a
[root@localhost ~]# echo "2023" > /var/www/html/2023/a/index.html
[root@localhost ~]# echo "2024" > /var/www/html/2024/a/index.html
[root@localhost ~]# tree /var/www/
/var/www/
└── html
├── 2023
│   └── a
│   └── index.html
└── 2024
└── a
└── index.html
# 检查配置文件语法是否错误,热加载nginx
[root@localhost ~]# nginx -t
[root@localhost ~]# systemctl reload nginx

# 游览器访问http://rewrite.tanke.love/2023/a

上述案例:当用户游览器访问http://rewrite.tanke.love/2023/a时,将永久重定向至http://rewrite.tanke.love/2024/a/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
192.168.174.20 rewrite.tanke.love
# 举例三:
[root@localhost ~]# vim rewrite03_server.conf
server {
listen 80;
server_name rewrite.tanke.love;
location / {
if ( $host ~* rewrite.tanke.love ) {
rewrite .* http://baidu.com permanent;
}
}
}

[root@localhost ~]# nginx -t
[root@localhost ~]# systemctl reload nginx
# 游览器访问http://rewrite.tanke.love

上述案例:当用户访问http://rewrite.tanke.love/是永久重定向至http://baidu.com

$host为客户端访问的域名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
192.168.174.20 rewrite.tanke.love
# 举例四:
[root@localhost ~]# vim rewrite04_server.conf
server {
listen 80;
server_name rewrite.tanke.love;
location /a {
if ( $host ~* rewrite.tanke.love ) {
rewrite .* http://192.168.21$request_uri permanent;
}
}
}

# 重定向主机配置文件准备
[root@localhost ~]# vim /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name localhost;
location /a {
root /usr/share/nginx/;
index index.html;
}
}
[root@localhost ~]# mkdir /usr/share/nginx/a
[root@localhost ~]# echo "192.168.172.21" > /usr/share/nginx/a/index.html

[root@localhost ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@localhost ~]# systemctl reload nginx

上述案例:当用户访问http://rewrite.tanke.love/a是永久重定向至http://192.168.174.21/a

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
192.168.174.20 rewrite.tanke.love

# http://rewrite.tanke.love/login/qf.html ==> http://rewrite.tanke.love/reg/login.html?user=qf

[root@localhost ~]# vim /etc/nginx/conf.d/rewrite06_server.conf
server {
listen 80;
server_name rewrite.tanke.love;

location /login {
root /usr/share/nginx/html;
rewrite ^/login/(.*)\.html$ http://$host/reg/login.html?user=$1;
}

location /reg {
root /usr/share/nginx/html;
index login.html;
}
}
[root@localhost ~]# mkdir -p /usr/share/nginx/html/reg
[root@localhost ~]# echo "login" > /usr/share/nginx/html/reg/login.html
[root@localhost ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@localhost ~]# systemctl reload nginx

定义了两个路径:/login和/reg。

对于/login路径,它设置了根目录为”/usr/share/nginx/html”。它还使用了一个正则表达式重写规则,将URL中的”/login/“后面的内容作为参数传递给”/reg/login.html”页面,并附加在URL中作为查询参数”user”的值。

对于/reg路径,它同样设置了根目录为”/usr/share/nginx/html”,并将默认索引文件设置为”login.html”。

这段配置的作用是将访问/login路径的请求重定向到/reg路径下的”login.html”页面,并将原始路径中的参数传递给该页面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
192.168.174.20 rewrite.tanke.love
# 举例7
# http://rewrite.tanke.love/qf/11-22-33/1.html ==> http://rewrite.tanke.love/qf/11/22/33/1.html

[root@localhost ~]# vim /etc/nginx/conf.d/rewrite07_server.conf
server {
listen 80;
server_name rewrite.tanke.love;
location /qf {
rewrite ^/qf/([0-9]+)-([0-9]+)-([0-9]+)(.*)$ /qf/$1/$2/$3$4 permanent;
}

location /qf/11/22/33 {
root /html;
index 1.html;
}
}

# 资源文件配置
[root@localhost ~]# mdkir -p /html/qf/11/22/33/
[root@localhost ~]# echo "qf" > /html/qf/11/22/33/1.html
[root@localhost ~]# nginx -t
[root@localhost ~]# systemctl reload nginx
# 游览器访问
http://rewrite.tanke.love/qf/11-22-33/1.html

定义了两个路径:/qf和/qf/11/22/33。

对于/qf路径,它使用了一个正则表达式重写规则,将URL中的”/qf/“后面的内容按照数字进行分组,并将这些数字作为参数传递给新的URL路径。新的URL路径为”/qf/11/22/33”,其中$1、$2、$3分别代表第一组、第二组和第三组的数字,$4表示剩余的字符串。这个重写规则使用了”permanent”标志,表示返回301永久重定向。

对于/qf/11/22/33路径,它设置了根目录为”/html”,并将默认索引文件设置为”1.html”。

这段配置的作用是将访问/qf路径的请求重定向到/qf/11/22/33路径下的”1.html”页面,并根据原始路径中的参数进行URL的重新组织。

9.2.4 set指令使用

​ set 指令是用于定义一个变量,并且赋值

1
server,location,if

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
C:\Windows\System32\drivers\etc\hosts # win域名解析

#http://liubei.tanke.love ==> http://rewrite.tanke.love/liubei
#http://guanyu.tanke.love ==> http://rewrite.tanke.love/guanyu

[root@localhost ~]# mkdir -p /usr/share/nginx/html/{liubei,guanyu}
[root@localhost ~]# echo "liubei.." > /usr/share/nginx/html/liubei/index.html
[root@localhost ~]# echo "guanyu.." > /usr/share/nginx/html/guanyu/index.html

编辑配置文件:
[root@localhost ~]# vim /etc/nginx/conf.d/set_server.conf
server {
listen 80;
server_name rewrite.tanke.love;

location / {
root /usr/share/nginx/html;
index index.html index.htm;
if ( $host ~* "^rewrite.tanke.love$" ) {
break;
}

if ( $host ~* "^(.*)\.tanke\.love$" ) {
set $user $1;
rewrite .* http://rewrite.tanke.love/$user permanent;
}
}
location /liubei {
root /usr/share/nginx/html;
index index.html index.hml;
}
location /guanyu {
root /usr/share/nginx/html;
index index.html index.hml;
}
}

[root@localhost ~]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@localhost ~]# systemctl reload nginx

该配置文件定义了一个监听在端口 80 上的服务器,并指定了服务器名称为 “rewrite.tanke.love”。它包含三个 location 块,分别对应不同的路径:

  • /:根路径,将请求映射到 /usr/share/nginx/html 目录下的 index.htmlindex.htm 文件。如果请求的主机名是 “rewrite.tanke.love”,则直接返回该文件;否则,如果主机名匹配正则表达式 ^(.*)\.tanke\.love$,则将主机名中的第一个部分作为变量 $user 的值,并将请求重定向到 http://rewrite.tanke.love/$user,使用永久重定向(301)。
  • /liubei:将请求映射到 /usr/share/nginx/html 目录下的 index.htmlindex.hml 文件。
  • /guanyu:将请求映射到 /usr/share/nginx/html 目录下的 index.htmlindex.hml 文件。

这个配置文件的作用是根据请求的主机名和路径来处理请求,并根据需要进行重定向。

9.2.5 return指令使用

​ return 指令用于返回状态码给客户端

1
2
# 作用域
server,location,if

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 如果访问的.sh结尾的文件则返回403操作拒绝错误
# http://rewrite.tanke.love/1.sh 返回403

[root@localhost ~]# vim /etc/nginx/conf.d/return_server.conf
server {
listen 80;
server_name rewrite.tanke.love;
#access_log /var/log/nginx/http_access.log main;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
}
location ~* \.sh$ {
return 403;
}
}
[root@localhost ~]# nginx -t
[root@localhost ~]# systemctl reload nginx

定义了一个监听在端口 80 上的服务器,并指定了服务器名称为 “rewrite.tanke.love”。它包含两个 location 块,分别对应不同的路径:

  • /:根路径,将请求映射到 /usr/share/nginx/html 目录下的 index.htmlindex.htm 文件。
  • ~* \.sh$:匹配以 .sh 结尾的文件名,返回 HTTP 状态码 403(禁止访问)。

这个配置文件的作用是处理请求,并根据请求的文件类型进行相应的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# https重定向
server {
listen 80;
server_name *.vip9999.top vip9999.top;

if ($host ~* "^www.vip9999.top$|^vip9999.top$" ) {
return 301 https://www.vip9999.top$request_uri;
}

if ($host ~* "^(.*).vip9999.top$" ) {
set $user $1;
return 301 https://www.vip9999.top/$user;
}

}

# Settings for a TLS enabled server.
server {
listen 443 ssl;
server_name www.vip9999.top;

location / {
root /usr/share/nginx/html;
index index.php index.html;
}

#pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
location ~ \.php$ {
root /usr/share/nginx/html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
ssl on;
ssl_certificate cert/214025315060640.pem;
ssl_certificate_key cert/214025315060640.key;
ssl_session_cache shared:SSL:1m;
ssl_session_timeout 10m;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
}

10、Nginx Location 指令详解

​ Nginx 的 HTTP 配置主要包括三个区块,结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
http { 						# 这个是协议级别
  include mime.types;
  default_type application/octet-stream;
  keepalive_timeout 65;
  gzip on;
    server { # 这个是服务级别
      listen 80;
      server_name localhost;
        location / { # 这个是请求级别
          root html;
          index index.html index.htm;
        }
      }
}
  1. 协议级别:这部分配置指定了使用的协议为HTTP,并包含了一个名为mime.types的文件,用于定义文件扩展名与MIME类型的映射关系。
  2. 服务级别:这部分配置指定了监听的端口号为80,服务器名称为localhost。虚拟主机
  3. 请求级别:这部分配置指定了根目录为html,默认的索引文件为index.html和index.htm。

10.1 Location 区块

  • location 是在 server 块中配置,根据不同的 URl使用不同的配置,来处理不同的请求
  • location 是有顺序的,会被第一个匹配的location 处理。

基本语法如下:

1
location [=|~|~*|^~|@] pattern{……}

10.2 location 前缀含义

1
2
3
4
5
6
7
=    表示精确匹配,优先级也是最高的,只有请求的 URI 与指定的字符串完全相等时才会匹配。
^~ 表示如果该模式匹配成功,将停止搜索其他匹配项并立即处理该请求。
~ 表示区分大小写的正则匹配
~* 表示不区分大小写的正则匹配
!~ 表示区分大小写不匹配的正则
!~* 表示不区分大小写不匹配的正则
/ 通用匹配,任何请求都会匹配到

10.2.1 location 配置示例

  1. 没有修饰符 /表示:必须以指定模式开始
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost ~]# mkdir -p /home/www/nginx/abc
[root@localhost ~]# echo "2.html" > /home/www/nginx/abc/2.html

server {
listen 80;
server_name www.tanke.love;

location /abc {
root /home/www/nginx;
index 2.html;
}
}
那么,如下是对的:
http://www.tanke.love/abc
  1. =表示:必须与指定的模式精确匹配
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@localhost ~]# echo "a" > /usr/share/nginx/html/a.html
[root@localhost ~]# echo "b" > /usr/share/nginx/html/b.html
server {
listen 80;
server_name www.tanke.love;

location / {
root /usr/share/nginx/html;
index a.html;
}

location = / {
root /usr/share/nginx/html;
index b.html;
}
}

进行测试:
http://www.tanke.love
http://www.tanke.love/a.html
  1. ~ 表示:指定的正则表达式要区分大小写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@localhost ~]# mkdir -p /home/www/nginx/{abc,ABC}
[root@localhost ~]# echo "abc" > /home/www/nginx/abc/2.html
[root@localhost ~]# echo "ABC" > /home/www/nginx/ABC/2.html


server {
server_name www.tanke.love;
location ~ /abc {
root /home/www/nginx;
index 2.html index.html;
}
location ~ /ABC {
root /home/www/nginx;
index 2.html index.html;
}
}

那么:
http://www.tanke.love/abc/
  1. ~* 表示:指定的正则表达式不区分大小写
1
2
3
4
5
6
7
8
9
server {
server_name www.tanke.love;
location ~* /abc {
root /home/www/nginx;
index 2.html index.html;
}
}
那么:
http://www.tanke.love/ABC/
  1. ^~ :类似于无修饰符的行为,也是以指定模式开始,不同的是,如果模式匹配,那么就停止搜索其他模式了。

10.2.2 location 查找顺序、优先级

1
2
3
4
5
6
7
8
= 大于 ^~  大于 ~|~*|!~|!~* 大于 /
多个location配置的情况下匹配顺序为:首先匹配 =,其次匹配^~, 其次是按正则匹配,最后是交给 / 通用匹配。当有匹配成功时候,停止匹配,按当前匹配规则处理请求。
================================================
(1) =:表示完全匹配;
(2) ^~:匹配URI的前缀,如果一个URI同时满足两个规则的话,匹配最长的规则;
(3) ~:匹配正则表达式,大小写敏感;
(4) ~*:匹配正则表达式,大小写不敏感;
优先级:(1)> (2) > (3) = (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
location 区段匹配示例

location = / {
  # 只匹配 / 的查询.
  [ configuration A ]
}
location / {
  # 匹配任何以 / 开始的查询,但是正则表达式与一些较长的字符串将被首先匹配。
  [ configuration B ]
}
location ^~ /images/ {
  # 匹配任何以 /images/ 开始的查询并且停止搜索,不检查正则表达式。
  [ configuration C ]
}
location ~* \.(gif|jpg|jpeg)$ {
  # 匹配任何以gif, jpg, or jpeg结尾的文件,但是所有 /images/ 目录的请求将在Configuration C中处理。
  [ configuration D ]
}
各请求的处理如下例:
/ → configuration A
/documents/document.html → configuration B
/images/1.gif → configuration C
/documents/1.jpg → configuration D

10.2.3 root 和alias 指令区别

在 Nginx 配置中,location 指令用于定义如何处理不同的 URL 请求。其中 rootalias 是两个常用的指令,它们的含义如下:

  1. rootroot 指令用于指定请求的根目录。当客户端发起请求时,Nginx 会将请求的 URI 与指定的根目录进行拼接,以确定实际的文件路径。例如,如果 root 设置为 /var/www/html,而客户端请求的是 /index.html,那么 Nginx 将会查找文件 /var/www/html/index.html
  2. aliasalias 指令用于指定请求的别名目录。与 root 不同,alias 不会将请求的 URI 与指定的目录进行拼接,而是直接使用指定的目录作为请求的根目录。例如,如果 alias 设置为 /var/www/images,而客户端请求的是 /index.jpg,那么 Nginx 将会查找文件 /var/www/images/index.jpg

需要注意的是,rootalias 只能选择其中一个来使用,不能同时使用。通常情况下,建议使用 root 指令来指定请求的根目录,因为它更加直观和简单。

举例:

1
2
3
4
5
6
7
8
9
10
11
12
server {
listen 80;
server_name rewrite.tanke.love;
location /img {
# root /var/www/image;
#若按照这种配置的话,则访问/img/目录下的文件时,nginx会去/var/www/image/img/目录下找文件
alias /var/www/image;
#若按照上述配置的话,则访问/img/目录里面的文件时,nginx会自动去/var/www/image/目录找文件
index index.html;
}
}
访问rewrite.tanke.love/img测试
  • alias 是一个目录别名的定义;
  • root 则是最上层目录的定义。
  • 还有一个重要的区别是alias后面必须要用“/”结束,否则会找不到文件的,而root则可有可无。