nginx知识点总结

发布于:2024-04-30 ⋅ 阅读:(24) ⋅ 点赞:(0)

一、DNS域名解析

域名是由一串用点分隔的字母和数字组成的互联网上某一台计算机或计算机组的名称,用于在数据传输时对计算机的定位标识(有时也指地理位置)。由于IP地址具有不方便记忆并且不能显示地址组织的名称和性质等缺点,人们设计出了域名,并通过网域名称系统(DNS)来将域名和IP地址相互映射,使人更方便地访问互联网,而不用去记住能够被机器直接读取的IP地址数串。

在Linux系统中,域名配置主要涉及到DNS(Domain Name System)的配置。具体配置如下:

  1. /etc/hosts文件:这是一个本地主机文件,用于存储IP地址和主机名之间的映射关系。当系统需要访问一个域名时,会先检查/etc/hosts文件中是否有对应的IP地址映射,如果有,则直接使用映射的IP地址进行访问。
  2. /etc/resolv.conf文件:这是一个DNS解析配置文件,用于设置DNS服务器的地址。当系统无法通过/etc/hosts文件获取域名对应的IP地址时,会向DNS服务器发送查询请求,获取域名对应的IP地址。

在Windows系统中,域名配置主要通过修改hosts文件来实现。具体操作步骤如下:

  1. 以管理员身份打开记事本。
  2. 打开位于“C:\Windows\System32\drivers\etc”文件夹中的hosts文件。如果文件属性为“只读”,需要去掉该勾选以便进行修改。
  3. 在hosts文件中添加或修改域名映射,格式为“IP地址 域名”。

在JDK中提供了一个与IP地址相关的InetAddress类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法。

InetAddress类的常用方法

方法声明

功能描述

InetAddress getByName(String host)

获取给定主机名的的IP地址,host参数表示指定主机

InetAddress getLocalHost()

获取本地主机地址

String getHostName()

获取本地IP地址的主机名

boolean isReachable(int timeout)

判断在限定时间内指定的IP地址是否可以访问

String getHostAddress()

获取字符串格式的原始IP地址

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Test01 {
    public static void main(String[] args) throws UnknownHostException {
        // 获取给定主机名的的IP地址,host参数表示指定主机
        InetAddress inetAddress = InetAddress.getByName("www.baidu.com");
        // 获取获取本地IP地址的主机名
        String hostName = inetAddress.getHostName();
        // 获取IP地址
        String address = inetAddress.getHostAddress();
        System.out.println("hostName:" + hostName);
        System.out.println("address:" + address);
    }
}

二、nginx概述

Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP代理服务器。它可以作为网站静态资源的web服务器,也可以作为其他应用服务器的反向代理服务器。同时,Nginx还具有负载均衡的功能。

Nginx的主要功能

  1. 静态资源服务:Nginx可以作为web服务器,直接处理静态文件请求,如HTML、CSS、JavaScript、图片等。
  2. 反向代理:Nginx可以作为反向代理服务器,将客户端的请求转发到后端的应用服务器,然后将应用服务器的响应返回给客户端。这种方式可以隐藏后端服务器的真实地址,提高系统的安全性,并且可以实现负载均衡,将请求分发到多个后端服务器上,提高系统的处理能力。
  3. 负载均衡:Nginx内置了负载均衡模块,可以实现多种负载均衡算法,如轮询、权重轮询、IP哈希等,根据需要将请求分发到不同的后端服务器上。
  4. HTTP缓存:Nginx支持HTTP缓存功能,可以缓存静态资源,减少对后端服务器的请求,提高系统的响应速度。
  5. SSL/TLS加密:Nginx支持SSL/TLS协议,可以对传输的数据进行加密,提高系统的安全性。

nginx的应用场景

1.反向代理 客户端发送请求达到Nginx服务器,Nginx转发到真实服务器访问,从而保证真实服务安全性;

2.负载均衡 能够对集群的节点实现负载均衡和故障转移,负载均衡算法:(轮询、权重、随机、hash等);

3.微服务网关入口 ,可以对微服务网关实现集群;

4.静态服务器 比Tomcat性能高很多,可以存放静态资源;-----推荐以后将静态资源存放到CDN

5.保护网站使用nginx+lua 实现对请求实现服务限流;

三、反向代理和正向代理

(一)反向代理

1.概念

  • 反向代理服务器位于用户与目标服务器之间,但对用户而言,反向代理服务器就相当于目标服务器,即用户直接访问反向代理服务器就可以获得目标服务器的资源。同时,用户不需要知道目标服务器的地址,也无须在用户端作任何设定。
  • 反向代理是针对服务器端的代理方式。客户端请求目标服务器的内容时,反向代理服务器会代替目标服务器处理这些请求,并将结果返回给客户端。客户端只会知道代理服务器的IP地址,而不知道实际的后端服务器集群的存在。反向代理通常用于负载均衡,将请求分发到多个后端服务器上,提高系统的处理能力。此外,反向代理还可以作为内容服务器的替身,提供安全防护,过滤掉不安全的请求。

2.作用:

  1. 反向代理服务器通常可用来作为Web加速,即使用反向代理作为Web服务器的前置机来降低网络和服务器的负载,提高访问效率。
  2. 负载均衡:通过将请求分发到多个后端服务器,反向代理可以有效地平衡负载,减少单个服务器的负担,从而提高系统的可伸缩性和整体性能。
  3. 安全性和访问控制:反向代理服务器通过实现身份验证、授权和防火墙功能,可以限制对后端服务器的访问,从而增强系统的安全性。同时,它还可以隐藏后端服务器的真实地址,进一步提高系统的安全性。
  4. 服务治理:反向代理服务器能够监控和管理后端服务器的状态,如进行健康检查、服务降级等操作,从而确保服务的稳定性和可用性。
  5. 缓存数据:反向代理服务器可以缓存原始资源服务器的资源,减少对原始资源服务器的请求次数,特别是一些静态的数据,如图片和文件。这不仅可以提高系统的性能,还可以降低网络带宽的使用。
  6. 提供加密连接:反向代理可以提供从防火墙外部代理服务器到防火墙内部安全内容服务器的加密连接,从而确保信息的安全传输。

3.特点:

  • 反向代理服务器是位于用户和目标服务器之间的。
  • 用户以为反射代理服务器就是真实服务器。用户不知道真实的服务器到底是谁。
  • 反向代理服务器保护服务端信息,称之为服务器端代理。

4.nginx实现反向代理机制

①hosts文件新增

127.0.0.1 www.boyatop.cn
127.0.0.1 member.boyatop.cn
127.0.0.1 order.boyatop.cn

②nginx配置

server {
        listen       80;
        server_name  www.boyatop.cn;
        location / {
            proxy_pass   http://127.0.0.1:8080/;
            index  index.html index.htm;
        }
    }

效果如下:

③使用不同域名访问不同服务器配置如下:

server {
        listen       80;
        server_name  www.boyatop.cn;

        location / {
            root   html;
        proxy_pass   http://127.0.0.1:8080/;
            index  index.html index.htm;
        }
}

server {
        listen       80;
        server_name  member.boyatop.cn;

        location / {
            root   html;
        proxy_pass   http://127.0.0.1:8081/;
            index  index.html index.htm;
        }
}

效果如下:

④使用不同url带不同名称访问两个不同的服务配置如下:

server {
        listen       80;
        server_name  member.boyatop.cn;

        location /member {
            root   html;
        proxy_pass   http://127.0.0.1:8081/;
            index  index.html index.htm;
        }
    location /order {
            root   html;
        proxy_pass   http://127.0.0.1:8080/;
            index  index.html index.htm;
        }
}

效果如下:

(二)正向代理

1.概念

  • 正向代理是位于客户端和目标服务器之间的代理服务器。客户端向代理服务器发送请求,并指定目标服务器,代理服务器将请求转交给目标服务器,并将从目标服务器获得的内容返回给客户端。正向代理需要客户端进行一些特别的设置才能使用。它的应用场景包括访问被限制的资源,例如“翻墙”等,此时正向代理可以隐藏客户端的IP地址,免受攻击。此外,正向代理还可以作为缓存,存储目标服务器返回的数据,提高访问速度。

2.作用

  1. 安全保护:正向代理服务器位于客户端和目标服务器之间,作为中间服务器,它能够帮助隐藏客户端的真实IP地址,从而提高客户端的安全性和隐私性。这对于防止恶意攻击和追踪用户活动具有重要意义。
  2. 访问控制:在企业或学校等组织内部,网络管理员可以通过配置正向代理服务器来限制或允许员工或学生对外部网站的访问。这有助于防止员工浏览不良网站、控制网络带宽使用,确保网络的合规性和高效性。
  3. 缓存和加速:当多个客户端同时请求相同的资源时,正向代理服务器可以将这些请求缓存起来,避免重复从目标服务器获取数据。这不仅可以减轻目标服务器的负载,还可以提高客户端的访问速度,提升用户体验。
  4. 内容过滤:代理服务器可以根据预设的规则对访问的内容进行过滤,阻止不良信息或恶意软件的传播。这对于保护用户免受网络威胁和垃圾信息的侵扰具有重要意义。
  5. 绕过地域限制或访问控制:有些网站或服务可能基于地理位置或其他因素限制用户的访问权限。通过正向代理,用户可以绕过这些限制,实现对特定资源的访问。

3.特点

  • 正向代理服务器是位于用户与服务器之间。
  • 用户请求时,非常明确目标服务器到底是谁,服务器不清楚到底是谁访问,以为是代理服务器直接发起的请求。
  • 正向代理服务器保护了用户的信息,所以称之为客户端代理。

正向代理,是在用户端的,比如需要访问某些国外网站,例如 github 在相关部门的允许情况下,我们可以使用vpn。


(三)代理总结

1.反向代理:是服务器端代理,只要用户访问服务器,都是反向代理,实现业务调用。

2.正向代理:是客户端代理,只要用户上网就使用正向代理,实现网络通信。

3.整个上网过程都是先正向后反向代理。

四、Nginx负载均衡策略

1、轮询(默认)

每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。

轮询配置

###定义上游服务器(需要被nginx真实代理访问的服务器) 默认是轮训机制
    upstream  backServer{
        server 127.0.0.1:8080;
        server 127.0.0.1:8081;
    }
    server {
        listen       80;
        server_name  upstream.boyatop.cn;
        location / {
        ### 指定上游服务器负载均衡服务器
        proxy_pass http://backServer;
            index  index.html index.htm;
        }
    }

2、指定权重

指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。

权重配置

###定义上游服务器(需要被nginx真实代理访问的服务器) 默认是轮训机制
    upstream  backServer{
        server 127.0.0.1:8080 weight=2;
        server 127.0.0.1:8081 weight=1;
    }
    server {
        listen       80;
        server_name  upstream.boyatop.cn;
        location / {
        ### 指定上游服务器负载均衡服务器
        proxy_pass http://backServer;
            index  index.html index.htm;
        }
    }

3、IP绑定 ip_hash

每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。

4、fair(第三方)

按后端服务器的响应时间来分配请求,响应时间短的优先分配。

5、url_hash(第三方)

按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。

Nginx负载均衡提供上游服务器(真实业务逻辑访问的服务器),负载均衡、故障转移、失败重试、容错、健康检查等。

当上游服务器(真实业务逻辑访问的服务器)发生故障时,可以转移到其他上游服务器(真实业务逻辑访问的服务器)。

五、Nginx Location指令详解

通过指定模式来与客户端请求的URI相匹配,基本语法如下:location [=|~|~*|^~|@] pattern{……}

1、没有修饰符

表示:必须以指定模式开始,如:

server {
  server_name www.boyatop.cn;
  location /member {
      proxy_pass   http://127.0.0.1:8080/;
      index  index.html index.htm;
  }
}
访问http://member.boyatop.cn/member 反向代理:http://127.0.0.1:8080/
那么,如下是对的:
http://member.boyatop.cn/member
http://member.boyatop.cn/member?p1
http://member.boyatop.cn/member/
http://member.boyatop.cn/Member

注意 proxy_pass http://127.0.0.1:8080/; 后面需要加上 / 才能反向代理到http://127.0.0.1:8080

proxy_pass不加/,会把域名转换为ip地址+端口号

proxy_pass加/,会把域名+location后边的转换为ip地址+端口号

2、=

表示:必须与指定的模式精确匹配

server {
  server_name www.boyatop.cn;
  location = /member {
      proxy_pass   http://127.0.0.1:8080/;
      index  index.html index.htm;
  }
}
访问http://www.boyatop.cn/member 反向代理:http://127.0.0.1:8080
那么,如下是对的:
http://www.boyatop.cn/member
http://www.boyatop.cn/member?p1
如下是错误:
http://www.boyatop.cn/member/
http://www.boyatop.cn/memberabc

3、~

表示:指定的正则表达式要区分大小写

server {
  server_name www.boyatop.cn;
  location ~ ^/member$ {
      proxy_pass   http://127.0.0.1:8080/;
      index  index.html index.htm;
  }
}
访问http://www.boyatop.cn/member 反向代理:http://127.0.0.1:8080
那么,如下是对的:
http://www.boyatop.cn/member
http://www.boyatop.cn/member?p1
如下是错误:
http://www.boyatop.cn/Member/
http://www.boyatop.cn/memberabc

4.~*

表示:指定的正则表达式不区分大小写

server {
  server_name www.boyatop.cn;
  location ~* ^/member$ {
      proxy_pass   http://127.0.0.1:8080/;
      index  index.html index.htm;
  }
}
访问http://www.boyatop.cn/member 反向代理:http://127.0.0.1:8080
那么,如下是对的:
http://www.boyatop.cn/member
http://www.boyatop.cn/member?p1
http://www.boyatop.cn/Member
如下是错误:
http://www.boyatop.cn/member/
http://www.boyatop.cn/memberabc

5、^~

类似于无修饰符的行为,也是以指定模式开始,不同的是,如果模式匹配,

那么就停止搜索其他模式了。

6、@

定义命名location区段,这些区段客户段不能访问,只可以由内部产生的请求来访问,如try_files或error_page等

查找顺序和优先级

1:带有“=“的精确匹配优先

2:没有修饰符的精确匹配

3:正则表达式按照他们在配置文件中定义的顺序

4:带有“^~”修饰符的,开头匹配

5:带有“~” 或“~*” 修饰符的,如果正则表达式与URI匹配

6:没有修饰符的,如果指定字符串与URI开头匹配

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

root 、alias指令区别

location /img/ {
    alias /var/www/image/;
}

若按照上述配置的话,则访问/img/目录里面的文件时,ningx会自动去/var/www/image/目录找文件

location /img/ {
    root /var/www/image;
}

若按照这种配置的话,则访问/img/目录下的文件时,nginx会去/var/www/image/img/目录下找文件。

alias是一个目录别名的定义,root则是最上层目录的定义。

区别:alias后面必须要用“/”结束,否则会找不到文件的,而root则可有可无

六、基于Nginx解决跨域问题

网站跨域问题是指在浏览器的同源策略下,当一个网页的JavaScript代码向不同源(协议、域名、端口号有任何一个不同即为不同源)发起请求时,会发生跨域问题。同源策略是浏览器的一种安全策略,它要求Web应用程序只能访问与当前页面具有相同协议、主机名和端口号的资源。如果Web应用程序需要访问不同源的资源,就需要进行跨域请求。但由于同源策略的限制,浏览器不允许跨域请求。这是出于安全考虑,防止恶意网站获取用户的敏感信息。

URL

说明

是否允许通信

http://www.a.com/a.js

http://www.a.com/b.js

同一域名下

允许

http://www.a.com/lab/a.js

http://www.a.com/script/b.js

同一域名下不同文件夹

允许

http://www.a.com:8000/a.js

http://www.a.com/b.js

同一域名,不同端口

不允许

http://www.a.com/a.js

https://www.a.com/b.js

同一域名,不同协议

不允许

http://www.a.com/a.js

http://192.168.110.11/b.js

域名和域名对应ip

不允许

http://www.a.com/a.js

http://script.a.com/b.js

主域相同,子域不同

不允许

http://www.a.com/a.js

http://a.com/b.js

同一域名,不同二级域名(同上)

不允许(cookie这种情况下也不允许访问)

http://www.cnblogs.com/a.js

http://www.a.com/b.js

不同域名

不允许

项目准备

创建两个springboot项目,A项目和B项目,A项目端口号为8080,B项目端口号为8081,A、B项目启动后,页面请求:http://localhost:8080/aJsp会跳转到A项目中的aJsp.jsp页面发送http://127.0.0.1:8081/getB请求,获取B项目中的信息,当A项目尝试访问B项目中的信息时,由于端口号不同,因此会产生跨域问题。

A项目

A项目的文件目录如下:

A项目要引入jsp页面,需要导入以下依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.0.2.RELEASE</version>
   </parent>

   <groupId>com.example</groupId>
   <artifactId>SpringbootJsp</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>SpringbootJsp</name>
   <description>SpringbootJsp</description>
   <properties>
      <java.version>1.8</java.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
      </dependency>
      <dependency>
         <groupId>org.apache.tomcat.embed</groupId>
         <artifactId>tomcat-embed-jasper</artifactId>
      </dependency>
   </dependencies>

   <build>
      <resources>
         <resource>
            <!--jsp 源文件路径-->
            <directory>src/main/webapp</directory>
            <!--jsp 目标文件路径-->
            <targetPath>META-INF/resources</targetPath>
            <!--需要拷贝的文件名表达式-->
            <includes>
               <include>*.*</include>
            </includes>
         </resource>
      </resources>
   </build>

</project>

A项目的application.yml配置文件如下:

server:
  port: 8080
spring:
  mvc:
    view:
      prefix: /WEB-INF/jsp/
      suffix: .jsp

A项目的controller如下:

package com.example.springbootjsp.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

@Controller
public class AController {
    @ResponseBody
    @RequestMapping("/")
    public String indext(){
        return "A被访问!!!";
    }

    @RequestMapping("/aJsp")
    public String aJsp(){
        return "aJsp";
    }
}

aJsp.jsp页面如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
         pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Insert title here</title>
    <script src="../../js/jquery.js"></script>
    <script>
        $(function (){
            $.ajax({
                type: "post",
                async: false,
                url: "http://127.0.0.1:8081/getB",
                dataType: "json",
                success:function (data){
                    alert(data["retCode"])
                },
                error: function (){
                    alert("fail!!!!")
                }
            })
        })
    </script>
</head>
<body>
<h1>A正在调用B!!!</h1>
</body>
</html>

B项目

B项目的application.yml如下:

server:
  port: 8081

B项目的controller如下:

package com.example.springbootb.controller;

import com.example.springbootb.Vo.Result;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class BController {

    @ResponseBody
    @RequestMapping("/")
    public String indext(){
        return "B被访问!!!";
    }

    @ResponseBody
    @RequestMapping("/getB")
    public Result getB(){
        System.out.println("B项目的getB!!!");
        Result result = new Result();
        result.setRetCode("200");
        result.setSetMsg("B信息获取成功!!");
        return result;
    }
}

B项目的Result封装类如下:

package com.example.springbootb.Vo;

public class Result {
    private String retCode;

    private String setMsg;

    public Result() {
    }

    public Result(String retCode, String setMsg) {
        this.retCode = retCode;
        this.setMsg = setMsg;
    }

    public String getRetCode() {
        return retCode;
    }

    public void setRetCode(String retCode) {
        this.retCode = retCode;
    }

    public String getSetMsg() {
        return setMsg;
    }

    public void setSetMsg(String setMsg) {
        this.setMsg = setMsg;
    }
}

跨域请求错误

解决方案

1.项目响应头设置允许跨域权限

response.setHeader("Access-Control-Allow-Origin", "");

这是最简单直接的方法,通过在服务器端设置响应头来允许任何源进行跨域请求。但请注意,使用

*会允许所有网站进行跨域请求,可能存在安全风险,特别是在涉及敏感信息或用户数据时。在小公司或测试环境中使用较为合适,但在生产环境中应谨慎使用。

//在B项目中加入
@ResponseBody
@RequestMapping("/getB")
public Result getB(){
    System.out.println("B项目的getB!!!");
    Result result = new Result();
    result.setRetCode("200");
    result.setSetMsg("B信息获取成功!!");
    HttpServletResponse resp = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
    resp.setHeader("Access-Control-Allow-Origin", "*");
    return result;
}

2.使用jsonp解决网站跨域问题 

JSONP 利用 <script> 标签没有跨域限制的漏洞,通过动态创建 <script>,以 GET 的方式请求数据。不过,JSONP 只支持 GET 请求,而且存在安全风险(如 XSS 攻击),因此不推荐在生产环境中使用。
缺点:只能支持Get请求 模拟脚本提交。
aJsp.jsp修改如下:

$(function (){
    $.ajax({
        type: "post",
        async: false,
        url: "http://127.0.0.1:8081/getB",
        // dataType: "json",
        dataType: "jsonp",
        jsonp: "jsonCallback",
        jsonpCallback: "callback",
        success:function (data){
            alert(data["retCode"])
        },
        error: function (){
            alert("fail!!!!")
        }
    })
})

BController如下

    @ResponseBody
    @RequestMapping("/getB")
    public void getB(HttpServletResponse response,String jsonpCallback) throws IOException {
        System.out.println("B项目的getB!!!");
        Result result = new Result();
        result.setRetCode("200");
        result.setSetMsg("B信息获取成功!!");
        PrintWriter writer = response.getWriter();
        writer.print(jsonpCallback+"("+result.toString()+")");
        writer.close();
    }

3.使用Nginx搭建API网关保持域名和端口一致 Location

通过Nginx代理请求,将前端页面的请求转发到后端服务,使前端页面和后端服务的域名、端口保持一致,从而避免跨域问题。这种方法适用于大型项目或微服务架构中,可以有效管理API请求和路由。

server{
  listen 80;
  server_name localhost;
  location / {
    root /usr/local/nginx/html;
    index index.html;
  }
  location /prod-api/ {
    proxy_pass http://62.234.175.16:8282/;
  }
}

4.使用微服务中的网关

在微服务架构中,可以使用专门的网关服务(如Spring Cloud Gateway、Zuul等)来管理跨域问题。网关可以统一处理跨域请求,将前端页面的请求转发到相应的微服务,并在响应头中添加跨域相关的设置。

5.HttpClient实现转发

通过HttpClient在服务器端发送请求到另一个服务器,并将结果返回给前端。这种方法虽然可以解决跨域问题,但会增加服务器的负载和网络延迟,因为每个请求都需要经过两次传输。此外,还需要处理可能出现的错误和异常情况。

jsonp是基于客户端的跨域解决。而httpclient是基于服务端的跨域解决

缺点:重复发送两次请求

引入依赖:

<!-- httpclient -->  
<dependency>  
    <groupId>org.apache.httpcomponents</groupId>  
    <artifactId>httpclient</artifactId>  
</dependency>  

Acontroller添加如下:

@ResponseBody
@RequestMapping("/forWardB")
public String forWardB() throws IOException {
    CloseableHttpClient httpclient = HttpClients.createDefault();
    HttpGet httpGet = new HttpGet("http://127.0.0.1:8081/getB");
    CloseableHttpResponse response = null;
    String content = null;
    try {
        // 执行请求,相当于敲完地址后按下回车。获取响应
        response = httpclient.execute(httpGet);
        // 判断返回状态是否为200
        if (response.getStatusLine().getStatusCode() == 200) {
            // 解析响应,获取数据
            content = EntityUtils.toString(response.getEntity(), "UTF-8");
            System.out.println(content);
        }
    } finally {
        if (response != null) {
            // 关闭资源
            response.close();
        }
        // 关闭浏览器
        httpclient.close();
    }
    return content;
}

HttpClientUtil

package com.example.springbootjsp.utils;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;

public class HttpClientUtil {

    public static String doGet(String url, Map<String, String> param) {

        // 创建Httpclient对象
        CloseableHttpClient httpclient = HttpClients.createDefault();

        String resultString = "";
        CloseableHttpResponse response = null;
        try {
            // 创建uri
            URIBuilder builder = new URIBuilder(url);
            if (param != null) {
                for (String key : param.keySet()) {
                    builder.addParameter(key, param.get(key));
                }
            }
            URI uri = builder.build();

            // 创建http GET请求
            HttpGet httpGet = new HttpGet(uri);

            // 执行请求
            response = httpclient.execute(httpGet);
            // 判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (response != null) {
                    response.close();
                }
                httpclient.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return resultString;
    }

    public static String doGet(String url) {
        return doGet(url, null);
    }

    public static String doPost(String url, Map<String, String> param) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建参数列表
            if (param != null) {
                List<NameValuePair> paramList = new ArrayList<>();
                for (String key : param.keySet()) {
                    paramList.add(new BasicNameValuePair(key, param.get(key)));
                }
                // 模拟表单
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(paramList);
                httpPost.setEntity(entity);
            }
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        return resultString;
    }

    public static String doPost(String url) {
        return doPost(url, null);
    }

    public static String doPostJson(String url, String json) {
        // 创建Httpclient对象
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        String resultString = "";
        try {
            // 创建Http Post请求
            HttpPost httpPost = new HttpPost(url);
            // 创建请求内容
            StringEntity entity = new StringEntity(json, ContentType.APPLICATION_JSON);
            httpPost.setEntity(entity);
            // 执行http请求
            response = httpClient.execute(httpPost);
            resultString = EntityUtils.toString(response.getEntity(), "utf-8");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                response.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        return resultString;
    }
}

解决跨域问题核心思想

解决跨域问题的核心思想是确保前端页面与后端服务之间的通信符合浏览器的同源策略,同时保证通信的安全性。具体方法包括设置响应头、使用代理或网关等方式来管理跨域请求和响应

Java项目中的实现

在Java项目中,可以使用过滤器(Filter)、拦截器(Interceptor)或AOP(面向切面编程)来统一处理跨域请求。这些技术可以在请求到达具体业务逻辑之前,对响应头进行设置,从而允许跨域请求。

七、nginx的使用

1.Nginx的启动

  • Nginx启动会生成2个进程:主进程与守护进程
    • 主进程:常用于提供反向代理服务。特点:占内存大。
    • 守护进程:防止主进程意外关闭。特点:占内存小。
  • Nginx启动需要占用80端口。
    • 当Nginx启动失败时,首先检查80端口是否被占用。

2.Nginx的命令

  • 工作目录:在Nginx.exe的根目录下运行。
  • 启动:
    • win:start nginx 
    • linux: ./nginx
  • 重启:
    • win:nginx -s reload
    • linux: ./nginx -s reload
  • 关闭:
    • win:nginx -s stop
    • linux: ./nginx -s stop
  • 说明:
    • 重启与关闭命令都是以启动命令为基础的。在启动成功之前,执行重启与关闭命令都会报错。

3.Nginx实现反向代理机制(通过配置文件完成)

1) Nginx实现反向代理

2) Nginx实现文件反向代理

3) Nginx实现域名代理

4) Nginx实现服务器集群和负载均衡

  • 服务器集群

  • 负载均衡实现
    • 方式:Nginx通过负载策略实现负载
    • 负载策略
      • 轮询机制:Nginx实现负载均衡的默认机制。
        • 实现方式:采取该机制时,Nginx会使用url请求平均访问服务器集群中的每一台服务器。
        • 实现方法:不需在upstream结构中添加任何代码。如上图所示。
      • 权重机制:
        • 实现方式:采取不同的权重使用url请求分布到不同侧重的服务器上。
        • 实现方法:

4. Nginx高级属性

1) down属性

  • 作用:显示指定集群中特定服务器宕机。
  • 使用方式:

  • 特点:当某一服务器被标识为down,所有访问都不会访问该服务器。

2) backup属性

  • 作用:显示指定集群中特定服务器为备用机。
  • 备用机的特点:平时不会使用备用机,当集群中的所有在用服务器宕机时,所有备用机才会自动启用。
  • 使用方式:

3) max_fails与fail_timeout属性

  • 作用:Nginx自动检测服务器状态,对宕机的服务器自动标识为down。
  • 属性详情:
    • max_fails:设定最大的失败次数,如果超过最大失败次数则将标识该服务器为down。
    • fails_timeout:失效的超时时间 60s表示:失效的超时时间为60秒。
  • 使用方式:

软负载与硬负载区别

1.软负载是基于服务器上安装的特定软件比如Nginx实现负载均衡

2.硬负载均衡是基于固定的硬件实现负载均衡比如F5


网站公告

今日签到

点亮在社区的每一天
去签到