Salmon的全栈知识 Salmon的全栈知识
首页
  • JavaSE
  • JavaWeb
  • Spring生态
  • JUC
  • JVM
  • Netty
  • Java各版本特性
  • 23种设计模式
  • Maven
  • Java常用框架
  • Dubbo
  • OpenFeign
  • Nacos
  • Zookeeper
  • Sentinel
  • Seata
  • SpringCloud Gateway
  • Apollo
  • Eureka
  • Go基础
  • Gin
  • SQL数据库

    • MySQL
    • Oracle
  • NoSQL数据库

    • Redis
    • MongoDB
    • ElasticSearch
  • 消息中间件

    • RabbitMQ
    • RocketMQ
    • Kafka
    • ActiveMQ
    • MQTT
    • NATS
  • 网关中间件

    • Nginx
  • Linux
  • Docker
  • Git
  • K8s
  • Solidity
  • Java
  • 计算机网络
  • 操作系统
GitHub (opens new window)
首页
  • JavaSE
  • JavaWeb
  • Spring生态
  • JUC
  • JVM
  • Netty
  • Java各版本特性
  • 23种设计模式
  • Maven
  • Java常用框架
  • Dubbo
  • OpenFeign
  • Nacos
  • Zookeeper
  • Sentinel
  • Seata
  • SpringCloud Gateway
  • Apollo
  • Eureka
  • Go基础
  • Gin
  • SQL数据库

    • MySQL
    • Oracle
  • NoSQL数据库

    • Redis
    • MongoDB
    • ElasticSearch
  • 消息中间件

    • RabbitMQ
    • RocketMQ
    • Kafka
    • ActiveMQ
    • MQTT
    • NATS
  • 网关中间件

    • Nginx
  • Linux
  • Docker
  • Git
  • K8s
  • Solidity
  • Java
  • 计算机网络
  • 操作系统
GitHub (opens new window)
npm

(进入注册为作者充电)

  • Nginx - 简介
  • Nginx - 环境准备
  • Nginx - 指令
  • Nginx - 核心配置文件
  • Nginx - 配置实例
  • Nginx - 静态资源部署
  • Nginx - 静态资源访问
    • Nginx - 反向代理
    • Nginx - 负载均衡
    • Nginx - 缓存集成
    • Nginx - 实现服务器端集群搭建
    • Nginx - 下载站点与用户认证模块
    • Nginx - 扩展模块
    • 《Nginx》笔记
    Salmon
    2021-04-01
    目录

    Nginx - 静态资源访问

    # Nginx的跨域问题解决

    这块内容,我们主要从以下方面进行解决:

    什么情况下会出现跨域问题?
    实例演示跨域问题
    具体的解决方案是什么?
    

    # 同源策略

    浏览器的同源策略:是一种约定,是浏览器最核心也是最基本的安全功能,如果浏览器少了同源策略,则浏览器的正常功能可能都会受到影响。

    同源: 协议、域名(IP)、端口相同即为同源

    http://192.168.200.131/user/1
    https://192.168.200.131/user/1
    不
    
    http://192.168.200.131/user/1
    http://192.168.200.132/user/1
    不
    
    http://192.168.200.131/user/1
    http://192.168.200.131:8080/user/1
    不
    
    http://www.nginx.com/user/1
    http://www.nginx.org/user/1
    不
    
    http://192.168.200.131/user/1
    http://192.168.200.131:8080/user/1
    不
    
    http://www.nginx.org:80/user/1
    http://www.nginx.org/user/1
    满足
    

    # 跨域问题

    简单描述下:

    有两台服务器分别为A,B,如果从服务器A的页面发送异步请求到服务器B获取数据,如果服务器A和服务器B不满足同源策略,则就会出现跨域问题。
    

    # 跨域问题的案例演示

    出现跨域问题会有什么效果?,接下来通过一个需求来给大家演示下:

    (1)nginx的html目录下新建一个a.html

    <html>
      <head>
            <meta charset="utf-8">
            <title>跨域问题演示</title>
            <script src="jquery.js"></script>
            <script>
                $(function(){
                    $("#btn").click(function(){
                            $.get('http://192.168.200.133:8080/getUser',function(data){
                                    alert(JSON.stringify(data));
                            });
                    });
                });
            </script>
      </head>
      <body>
            <input type="button" value="获取数据" id="btn"/>
      </body>
    </html>
    
    

    (2)在nginx.conf配置如下内容

    server{
            listen  8080;
            server_name localhost;
            location /getUser{
                    default_type application/json;
                    return 200 '{"id":1,"name":"TOM","age":18}';
            }
    }
    server{
    	listen 	80;
    	server_name localhost;
    	location /{
    		root html;
    		index index.html;
    	}
    }
    

    (3)通过浏览器访问测试

    1588004913681

    # 解决方案

    使用add_header指令,该指令可以用来添加一些头信息

    语法 add_header name value...
    默认值 —
    位置 http、server、location

    此处用来解决跨域问题,需要添加两个头信息,一个是Access-Control-Allow-Origin,Access-Control-Allow-Methods

    Access-Control-Allow-Origin: 直译过来是允许跨域访问的源地址信息,可以配置多个(多个用逗号分隔),也可以使用*代表所有源

    Access-Control-Allow-Methods:直译过来是允许跨域访问的请求方式,值可以为 GET POST PUT DELETE...,可以全部设置,也可以根据需要设置,多个用逗号分隔

    具体配置方式

    location /getUser{
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE;
        default_type application/json;
        return 200 '{"id":1,"name":"TOM","age":18}';
    }
    

    # 静态资源防盗链

    # 什么是资源盗链

    资源盗链指的是此内容不在自己服务器上,而是通过技术手段,绕过别人的限制将别人的内容放到自己页面上最终展示给用户。以此来盗取大网站的空间和流量。简而言之就是用别人的东西成就自己的网站。

    效果演示

    京东:https://img14.360buyimg.com/n7/jfs/t1/101062/37/2153/254169/5dcbd410E6d10ba22/4ddbd212be225fcd.jpg

    百度:https://pics7.baidu.com/feed/cf1b9d16fdfaaf516f7e2011a7cda1e8f11f7a1a.jpeg?token=551979a23a0995e5e5279b8fa1a48b34&s=BD385394D2E963072FD48543030030BB

    我们自己准备一个页面,在页面上引入这两个图片查看效果

    从上面的效果,可以看出来,下面的图片地址添加了防止盗链的功能,京东这边我们可以直接使用其图片。

    # Nginx防盗链的实现原理:

    了解防盗链的原理之前,我们得先学习一个HTTP的头信息Referer,当浏览器向web服务器发送请求的时候,一般都会带上Referer,来告诉浏览器该网页是从哪个页面链接过来的。

    后台服务器可以根据获取到的这个Referer信息来判断是否为自己信任的网站地址,如果是则放行继续访问,如果不是则可以返回403(服务端拒绝访问)的状态信息。

    在本地模拟上述的服务器效果:

    Nginx防盗链的具体实现:

    valid_referers:nginx会通就过查看referer自动和valid_referers后面的内容进行匹配,如果匹配到了就将$invalid_referer变量置0,如果没有匹配到,则将$invalid_referer变量置为1,匹配的过程中不区分大小写。

    语法 valid_referers none|blocked|server_names|string...
    默认值 —
    位置 server、location

    none: 如果Header中的Referer为空,允许访问

    blocked:在Header中的Referer不为空,但是该值被防火墙或代理进行伪装过,如不带"http://" 、"https://"等协议头的资源允许访问。

    server_names:指定具体的域名或者IP

    string: 可以支持正则表达式和*的字符串。如果是正则表达式,需要以~开头表示,例如

    location ~*\.(png|jpg|gif){
               valid_referers none blocked www.baidu.com 192.168.200.222 *.example.com example.*  www.example.org  ~\.google\.;
               if ($invalid_referer){
                    return 403;
               }
               root /usr/local/nginx/html;
    
    }
    

    遇到的问题:图片有很多,该如何批量进行防盗链?

    # 针对目录进行防盗链

    配置如下:

    location /images {
               valid_referers none blocked www.baidu.com 192.168.200.222 *.example.com example.*  www.example.org  ~\.google\.;
               if ($invalid_referer){
                    return 403;
               }
               root /usr/local/nginx/html;
    
    }
    

    这样我们可以对一个目录下的所有资源进行翻到了操作。

    遇到的问题:Referer的限制比较粗,比如随意加一个Referer,上面的方式是无法进行限制的。那么这个问题改如何解决?

    此处我们需要用到Nginx的第三方模块ngx_http_accesskey_module,第三方模块如何实现盗链,如果在Nginx中使用第三方模块的功能,这些我们在后面的Nginx的模块篇再进行详细的讲解。

    # Rewrite功能配置

    Rewrite是Nginx服务器提供的一个重要基本功能,是Web服务器产品中几乎必备的功能。主要的作用是用来实现URL的重写。

    注意:Nginx服务器的Rewrite功能的实现依赖于PCRE的支持,因此在编译安装Nginx服务器之前,需要安装PCRE库。Nginx使用的是ngx_http_rewrite_module模块来解析和处理Rewrite功能的相关配置。

    # "地址重写"与"地址转发"

    重写和转发的区别:

    地址重写浏览器地址会发生变化而地址转发则不变
    一次地址重写会产生两次请求而一次地址转发只会产生一次请求
    地址重写到的页面必须是一个完整的路径而地址转发则不需要
    地址重写因为是两次请求所以request范围内属性不能传递给新页面而地址转发因为是一次请求所以可以传递值
    地址转发速度快于地址重写
    

    # Rewrite规则

    # set指令

    该指令用来设置一个新的变量。

    语法 set $variable value;
    默认值 —
    位置 server、location、if

    variable:变量的名称,该变量名称要用"$"作为变量的第一个字符,且不能与Nginx服务器预设的全局变量同名。

    value:变量的值,可以是字符串、其他变量或者变量的组合等。

    # Rewrite常用全局变量

    变量 说明
    $args 变量中存放了请求URL中的请求指令。比如http://192.168.200.133:8080?arg1=value1&args2=value2中的"arg1=value1&arg2=value2",功能和$query_string一样
    $http_user_agent 变量存储的是用户访问服务的代理信息(如果通过浏览器访问,记录的是浏览器的相关版本信息)
    $host 变量存储的是访问服务器的server_name值
    $document_uri 变量存储的是当前访问地址的URI。比如http://192.168.200.133/server?id=10&name=zhangsan中的"/server",功能和$uri一样
    $document_root 变量存储的是当前请求对应location的root值,如果未设置,默认指向Nginx自带html目录所在位置
    $content_length 变量存储的是请求头中的Content-Length的值
    $content_type 变量存储的是请求头中的Content-Type的值
    $http_cookie 变量存储的是客户端的cookie信息,可以通过add_header Set-Cookie 'cookieName=cookieValue'来添加cookie数据
    $limit_rate 变量中存储的是Nginx服务器对网络连接速率的限制,也就是Nginx配置中对limit_rate指令设置的值,默认是0,不限制。
    $remote_addr 变量中存储的是客户端的IP地址
    $remote_port 变量中存储了客户端与服务端建立连接的端口号
    $remote_user 变量中存储了客户端的用户名,需要有认证模块才能获取
    $scheme 变量中存储了访问协议
    $server_addr 变量中存储了服务端的地址
    $server_name 变量中存储了客户端请求到达的服务器的名称
    $server_port 变量中存储了客户端请求到达服务器的端口号
    $server_protocol 变量中存储了客户端请求协议的版本,比如"HTTP/1.1"
    $request_body_file 变量中存储了发给后端服务器的本地文件资源的名称
    $request_method 变量中存储了客户端的请求方式,比如"GET","POST"等
    $request_filename 变量中存储了当前请求的资源文件的路径名
    $request_uri 变量中存储了当前请求的URI,并且携带请求参数,比如http://192.168.200.133/server?id=10&name=zhangsan中的"/server?id=10&name=zhangsan"

    # if指令

    该指令用来支持条件判断,并根据条件判断结果选择不同的Nginx配置。

    语法 if (condition){...}
    默认值 —
    位置 server、location

    condition为判定条件,可以支持以下写法:

    1. 变量名。如果变量名对应的值为空或者是0,if都判断为false,其他条件为true。
    if ($param){
    	
    }
    
    2. 使用"="和"!="比较变量和字符串是否相等,满足条件为true,不满足为false
    
    if ($request_method = POST){
    	return 405;
    }
    

    注意:此处和Java不太一样的地方是字符串不需要添加引号。

    1. 使用正则表达式对变量进行匹配,匹配成功返回true,否则返回false。变量与正则表达式之间使用"~","~*","!~","!~*"来连接。

      "~"代表匹配正则表达式过程中区分大小写,

      "~*"代表匹配正则表达式过程中不区分大小写

      "!~"和"!~*"刚好和上面取相反值,如果匹配上返回false,匹配不上返回true

    if ($http_user_agent ~ MSIE){
    	#$http_user_agent的值中是否包含MSIE字符串,如果包含返回true
    }
    

    注意:正则表达式字符串一般不需要加引号,但是如果字符串中包含"}"或者是";"等字符时,就需要把引号加上。

    1. 判断请求的文件是否存在使用"-f"和"!-f",

      当使用"-f"时,如果请求的文件存在返回true,不存在返回false。

      当使用"!f"时,如果请求文件不存在,但该文件所在目录存在返回true,文件和目录都不存在返回false,如果文件存在返回false

    if (-f $request_filename){
    	#判断请求的文件是否存在
    }
    if (!-f $request_filename){
    	#判断请求的文件是否不存在
    }
    
    1. 判断请求的目录是否存在使用"-d"和"!-d",

      当使用"-d"时,如果请求的目录存在,if返回true,如果目录不存在则返回false

      当使用"!-d"时,如果请求的目录不存在但该目录的上级目录存在则返回true,该目录和它上级目录都不存在则返回false,如果请求目录存在也返回false.

    2. 判断请求的目录或者文件是否存在使用"-e"和"!-e"

      当使用"-e",如果请求的目录或者文件存在时,if返回true,否则返回false.

      当使用"!-e",如果请求的文件和文件所在路径上的目录都不存在返回true,否则返回false

    3. 判断请求的文件是否可执行使用"-x"和"!-x"

      当使用"-x",如果请求的文件可执行,if返回true,否则返回false

      当使用"!-x",如果请求文件不可执行,返回true,否则返回false

    # break指令

    该指令用于中断当前相同作用域中的其他Nginx配置。与该指令处于同一作用域的Nginx配置中,位于它前面的指令配置生效,位于后面的指令配置无效。

    语法 break;
    默认值 —
    位置 server、location、if

    例子:

    location /{
    	if ($param){
    		set $id $1;
    		break;
    		limit_rate 10k;
    	}
    }
    

    # return指令

    该指令用于完成对请求的处理,直接向客户端返回响应状态代码。在return后的所有Nginx配置都是无效的。

    语法 return code [text];
    return code URL;
    return URL;
    默认值 —
    位置 server、location、if

    code:为返回给客户端的HTTP状态代理。可以返回的状态代码为0~999的任意HTTP状态代理

    text:为返回给客户端的响应体内容,支持变量的使用

    URL:为返回给客户端的URL地址

    # rewrite指令

    该指令通过正则表达式的使用来改变URI。可以同时存在一个或者多个指令,按照顺序依次对URL进行匹配和处理。

    URL和URI的区别:

    URI:统一资源标识符
    URL:统一资源定位符
    
    语法 rewrite regex replacement [flag];
    默认值 —
    位置 server、location、if

    regex:用来匹配URI的正则表达式

    replacement:匹配成功后,用于替换URI中被截取内容的字符串。如果该字符串是以"http://"或者"https://"开头的,则不会继续向下对URI进行其他处理,而是直接返回重写后的URI给客户端。

    flag:用来设置rewrite对URI的处理行为,可选值有如下:

    • last:
    • break
    • redirect
    • permanent

    # rewrite_log指令

    该指令配置是否开启URL重写日志的输出功能。

    语法 rewrite_log on|off;
    默认值 rewrite_log off;
    位置 http、server、location、if

    开启后,URL重写的相关日志将以notice级别输出到error_log指令配置的日志文件汇总。

    # Rewrite的案例

    # 域名跳转

    》问题分析

    先来看一个效果,如果我们想访问京东网站,大家都知道我们可以输入www.jd.com,但是同样的我们也可以输入www.360buy.com同样也都能访问到京东网站。这个其实是因为京东刚开始的时候域名就是www.360buy.com,后面由于各种原因把自己的域名换成了www.jd.com, 虽然说域名变量,但是对于以前只记住了www.360buy.com的用户来说,我们如何把这部分用户也迁移到我们新域名的访问上来,针对于这个问题,我们就可以使用Nginx中Rewrite的域名跳转来解决。

    》环境准备

    • 准备两个域名 www.360buy.com | www.jd.com
    vim /etc/hosts
    
    192.168.200.133 www.360buy.com
    192.168.200.133 www.jd.com
    
    • 在/usr/local/nginx/html/hm目录下创建一个访问页面
    <html>
    	<title></title>
    	<body>
    		<h1>欢迎来到我们的网站</h1>
    	</body>
    </html>
    
    • 通过Nginx实现当访问www.访问到系统的首页
    server {
    	listen 80;
    	server_name www.hm.com;
    	location /{
    		root /usr/local/nginx/html/hm;
    		index index.html;
    	}
    }
    

    》通过Rewrite完成将www.360buy.com的请求跳转到www.jd.com

    server {
    	listen 80;
    	server_name www.360buy.com;
    	rewrite ^/ http://www.jd.com permanent;
    }
    

    问题描述:如何在域名跳转的过程中携带请求的URI?

    修改配置信息

    server {
    	listen 80;
    	server_name www.itheima.com;
    	rewrite ^(.*) http://www.hm.com$1 permanent;
    }
    

    问题描述:我们除了上述说的www.jd.com 、www.360buy.com其实还有我们也可以通过www.jingdong.com来访问,那么如何通过Rewrite来实现多个域名的跳转?

    添加域名

    vim /etc/hosts
    192.168.200.133 www.jingdong.com
    

    修改配置信息

    server{
    	listen 80;
    	server_name www.360buy.com www.jingdong.com;
    	rewrite ^(.*) http://www.jd.com$1 permanent;
    }
    

    # 域名镜像

    上述案例中,将www.360buy.com 和 www.jingdong.com都能跳转到www.jd.com,那么www.jd.com我们就可以把它起名叫主域名,其他两个就是我们所说的镜像域名,当然如果我们不想把整个网站做镜像,只想为其中某一个子目录下的资源做镜像,我们可以在location块中配置rewrite功能,比如:

    server {
    	listen 80;
    	server_name rewrite.myweb.com;
    	location ^~ /source1{
    		rewrite ^/resource1(.*) http://rewrite.myweb.com/web$1 last;
    	}
    	location ^~ /source2{
    		rewrite ^/resource2(.*) http://rewrite.myweb.com/web$1 last;
    	}
    }
    

    # 独立域名

    一个完整的项目包含多个模块,比如购物网站有商品商品搜索模块、商品详情模块已经购物车模块等,那么我们如何为每一个模块设置独立的域名。

    需求:

    http://search.hm.com  访问商品搜索模块
    http://item.hm.com	  访问商品详情模块
    http://cart.hm.com	  访问商品购物车模块
    
    server{
    	listen 80;
    	server_name search.hm.com;
    	rewrite ^(.*) http://www.hm.com/bbs$1 last;
    }
    server{
    	listen 81;
    	server_name item.hm.com;
    	rewrite ^(.*) http://www.hm.com/item$1 last;
    }
    server{
    	listen 82;
    	server_name cart.hm.com;
    	rewrite ^(.*) http://www.hm.com/cart$1 last;
    }
    

    # 目录自动添加"/"

    问题描述

    通过一个例子来演示下问题:

    server {
    	listen	80;
    	server_name localhost;
    	location / {
    		root html;
    		index index.html;
    	}
    }
    
    

    要想访问上述资源,很简单,只需要通过http://192.168.200.133直接就能访问,地址后面不需要加/,但是如果将上述的配置修改为如下内容:

    server {
    	listen	80;
    	server_name localhost;
    	location /hm {
    		root html;
    		index index.html;
    	}
    }
    

    这个时候,要想访问上述资源,按照上述的访问方式,我们可以通过http://192.168.200.133/hm/来访问,但是如果地址后面不加斜杠,页面就会出问题。如果不加斜杠,Nginx服务器内部会自动做一个301的重定向,重定向的地址会有一个指令叫server_name_in_redirect on|off;来决定重定向的地址:

    如果该指令为on
    	重定向的地址为:  http://server_name/目录名/;
    如果该指令为off
    	重定向的地址为:  http://原URL中的域名/目录名/;
    

    所以就拿刚才的地址来说,http://192.168.200.133/hm如果不加斜杠,那么按照上述规则,如果指令server_name_in_redirect为on,则301重定向地址变为 http://localhost/hm/,如果为off,则301重定向地址变为http://192.168.200.133/ht/。后面这个是正常的,前面地址就有问题。

    注意server_name_in_redirect指令在Nginx的0.8.48版本之前默认都是on,之后改成了off,所以现在我们这个版本不需要考虑这个问题,但是如果是0.8.48以前的版本并且server_name_in_redirect设置为on,我们如何通过rewrite来解决这个问题?

    解决方案

    我们可以使用rewrite功能为末尾没有斜杠的URL自动添加一个斜杠

    server {
    	listen	80;
    	server_name localhost;
    	server_name_in_redirect on;
    	location /hm {
    		if (-d $request_filename){
    			rewrite ^/(.*)([^/])$ http://$host/$1$2/ permanent;
    		}
    	}
    }
    

    # 合并目录

    搜索引擎优化(SEO)是一种利用搜索引擎的搜索规则来提供目的网站的有关搜索引擎内排名的方式。我们在创建自己的站点时,可以通过很多中方式来有效的提供搜索引擎优化的程度。其中有一项就包含URL的目录层级一般不要超过三层,否则的话不利于搜索引擎的搜索也给客户端的输入带来了负担,但是将所有的文件放在一个目录下又会导致文件资源管理混乱并且访问文件的速度也会随着文件增多而慢下来,这两个问题是相互矛盾的,那么使用rewrite如何解决上述问题?

    举例,网站中有一个资源文件的访问路径时 /server/11/22/33/44/20.html,也就是说20.html存在于第5级目录下,如果想要访问该资源文件,客户端的URL地址就要写成 http://www.web.name/server/11/22/33/44/20.html,

    server {
    	listen 80;
    	server_name www.web.name;
    	location /server{
    		root html;
    	}
    }
    

    但是这个是非常不利于SEO搜索引擎优化的,同时客户端也不好记.使用rewrite我们可以进行如下配置:

    server {
    	listen 80;
    	server_name www.web.name;
    	location /server{
    		rewrite ^/server-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)\.html$ /server/$1/$2/$3/$4/$5.html last;
    	}
    }
    

    这样的花,客户端只需要输入http://www.web.name/server-11-22-33-44-20.html就可以访问到20.html页面了。这里也充分利用了rewrite指令支持正则表达式的特性。

    # 防盗链

    防盗链之前我们已经介绍过了相关的知识,在rewrite中的防盗链和之前将的原理其实都是一样的,只不过通过rewrite可以将防盗链的功能进行完善下,当出现防盗链的情况,我们可以使用rewrite将请求转发到自定义的一张图片和页面,给用户比较好的提示信息。下面我们就通过根据文件类型实现防盗链的一个配置实例:

    server{
    	listen 80;
    	server_name www.web.com;
    	locatin ~* ^.+\.(gif|jpg|png|swf|flv|rar|zip)${
    		valid_referers none blocked server_names *.web.com;
    		if ($invalid_referer){
    			rewrite ^/ http://www.web.com/images/forbidden.png;
    		}
    	}
    }
    

    根据目录实现防盗链配置:

    server{
    	listen 80;
    	server_name www.web.com;
    	location /file/{
    		root /server/file/;
    		valid_referers none blocked server_names *.web.com;
    		if ($invalid_referer){
    			rewrite ^/ http://www.web.com/images/forbidden.png;
    		}
    	}
    }
    
    上次更新: 2025/07/23, 01:37:33
    Nginx - 静态资源部署
    Nginx - 反向代理

    ← Nginx - 静态资源部署 Nginx - 反向代理→

    Theme by Vdoing | Copyright © 2022-2025 Salmon's Blog
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式