Envoy HTTP服务韧性-Day04

服务韧性,从某种意义上来讲,就是局部故障的自动处理逻辑,代表了网格的一种自愈能力的表现。

1. 混沌工程和故障注入

1. 前言

复杂的分布式服务体系中,故障发生的随机性和不可预测性都大大增加,随着服务化、微服务和持续集成的逐渐普及,快速迭代的门槛越来越低,但是对复杂系统稳定性的考验却在成倍增长。
分布式系统天生包含大量的交互、依赖点,故障点层出不穷: 硬盘故障、网络故障、流量激增压垮某些组件、外部系统故障、不合理的降级方案等等都会成为常见问题;
人力无法改变此种局面,更需要做的是致力于在这些异常被触发之前尽可能多地识别出会导致此类异常的系统脆弱环节或组件,进而有针对性地对其加固,以避免故障发生,打造出更具弹性的系统,这正是混沌工程诞生的原因之一;

1.2 什么是混沌工程

混沌工程是一种通过实证探究的方式来理解系统行为的方法,也是一套通过在系统基础设施上进行实验,主动找出系统中的脆弱环节的方法学;

混沌工程是在分布式系统上进行实验的学科,旨在提升系统容错性,建立系统抵御生产环境中发生不可预知问题的信心。

混沌工程的意义在于,能让复杂系统中根深蒂固的混乱和不稳定性浮出表面,让工程师可以更全面地理解这些系统性固有现象,从而在分布式系统中实现更好的工程设计,不断提高系统弹性。

1.3 混沌工程和故障注入

(1)混沌工程是发现新信息的实验过程,而故障注入则是对一个特定的条件或变量的测试方法。

(2)测试和实验的区别
测试通过仅产生二元的结果,即真或者假,从而用于判定测试是否通过,但测试并不能发掘出系统未知的或尚不明确的认知,它仅仅是对已知的系统属性可能的取值进行测验;
而实验可以产生新的认知,而且通常还能开辟出一个更广袤的相对复杂系统的认知空间;

(3)混沌工程并非是简单的制造服务中断等故障。

1.4 HTTP故障注入过滤器

1.4.1 介绍

故障注入在Envov中的实现上类似于重定向、重写和重试,它们通过修改HTTP请求或应答的内容完成;
它由专用的故障注入过滤器 (faultinjection)实现,用于测试微服务对不同形式的故障韧性;
需要使用名称envoy.filters.http.fault配置此过滤器。
通过用户指定的错误代码注入延迟 (delay) 和请求中止 (bort) ,从而模拟出分阶段的不同故障情形。
故障范围仅限于通过网络进行通信的应用程序可观察到的范围,不支持模拟本地主机上的CPU和磁盘故障。

过滤器配置格式
在这里插入图片描述

1.4.2 HTTP故障注入

1.4.2.1 注入“延迟” 定义方式
{
  "fixed_delay": "{……}" # 持续时长,将请求转发至上游主机之前添加固定延迟;
  "header_delay": "{……}" # 基于HTTP标头的指定控制故障延迟;
  "percentage": "{……}" # 将注入延迟的 操作/链接/请求(operations/connetions/requests)的百分比,意思就是将错误 注入多大的比例到请你去操作上;
  # 百分比:numerator参数指定分子,denominator指定分母
}
1.4.2.2 注入“请求终止” 定义方式
{
  "http_status": "{……}" # 用于终止HTTP请求的状态码: http_status、grpc_status和header_status三者仅能且必须定义一个;
  "grpc_status": "{……}" # 用于终止GRPC请求的状态码;
  "header_abort": "{……}" # 由HTTP标头控制的终止;
  "percentage": "{……}" # 在多大的流量比例中,注入错误
}
1.4.2.3 响应报文的速率限制
{
  "pixed_limit": "{limit_kbps: ...}" # 固定速率,单位kib/s;
  "header_limit": "{}" # 限制为HTTP首部的指定速率;
  "percentage": "{}" # 在多大的流量比例中,注入错误
}

1.4.3 故障注入示例

1.4.3.1 使用abort,为10%的请求注入503故障
http_filters: # http过滤器
- name: envoy.filters.http.fault # 指明使用的故障过滤器名称
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault # 指明类型
	max_active_aults: 100 # 活跃的故障数最多不能超过100个(防止故障数多,对系统造成影响,毕竟如果有1万个请求,按照下面的配置,就会有1000个503了)
	abort: # 终止故障配置
      http_status: 503
      percentage:
        numerator: 10 # 在这10%的流量中注入503故障
        denominator: HUNDRED
1.4.3.2 使用delay,为10%的请求注入固定的10秒延迟
http_filters:
- name: envoy.filters.http.fault
  typed config:
    "@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
	max_active_faults: 100
    delay:
      fixed delay: 10s
      percentage:
        numerator: 10
		denominator: HUNDRED

1.4.4 故障注入演示

[root@k8s-harbor01 ~]# cd servicemesh_in_practise-MageEdu_N66/HTTP-Connection-Manager/fault-injection/
[root@k8s-harbor01 fault-injection]# ls
curl_format.txt      front-envoy.yaml  send-requests.sh                          service-envoy-fault-injection-delay.yaml
docker-compose.yaml  README.md         service-envoy-fault-injection-abort.yaml  service-envoy.yaml

1.4.4.1 配置文件展示
# curl_format.txt
[root@k8s-harbor01 fault-injection]# cat curl_format.txt
    time_namelookup:  %{time_namelookup}\n
       time_connect:  %{time_connect}\n
    time_appconnect:  %{time_appconnect}\n
   time_pretransfer:  %{time_pretransfer}\n
      time_redirect:  %{time_redirect}\n
 time_starttransfer:  %{time_starttransfer}\n
                    ----------\n
         time_total:  %{time_total}\n


# docker-compose.yaml
[root@k8s-harbor01 fault-injection]# cat docker-compose.yaml
version: '3.3'

services:
  envoy:
    image: envoyproxy/envoy-alpine:v1.21-latest
    environment:
      - ENVOY_UID=0
      - ENVOY_GID=0
    volumes:
    - ./front-envoy.yaml:/etc/envoy/envoy.yaml
    networks:
      envoymesh:
        ipv4_address: 172.31.62.10
        aliases:
        - front-proxy
    expose:
      # Expose ports 80 (for general traffic) and 9901 (for the admin server)
      - "80"
      - "9901"

  service_blue:
    image: ikubernetes/servicemesh-app:latest
    volumes:
      - ./service-envoy-fault-injection-abort.yaml:/etc/envoy/envoy.yaml
    networks:
      envoymesh:
        aliases:
          - service_blue
          - colored
    environment:
      - SERVICE_NAME=blue
    expose:
      - "80"

  service_green:
    image: ikubernetes/servicemesh-app:latest
    networks:
      envoymesh:
        aliases:
          - service_green
          - colored
    environment:
      - SERVICE_NAME=green
    expose:
      - "80"

  service_red:
    image: ikubernetes/servicemesh-app:latest
    volumes:
      - ./service-envoy-fault-injection-delay.yaml:/etc/envoy/envoy.yaml
    networks:
      envoymesh:
        aliases:
          - service_red
          - colored
    environment:
      - SERVICE_NAME=red
    expose:
      - "80"

networks:
  envoymesh:
    driver: bridge
    ipam:
      config:
        - subnet: 172.31.62.0/24

# front-envoy.yaml
[root@k8s-harbor01 fault-injection]# cat front-envoy.yaml
admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

layered_runtime:
  layers:
  - name: admin
    admin_layer: {}

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: backend
              domains:
              - "*"
              routes:
              - match:
                  prefix: "/service/blue"
                route:
                  cluster: blue_abort
              - match:
                  prefix: "/service/red"
                route:
                  cluster: red_delay
              - match:
                  prefix: "/service/green"
                route:
                  cluster: green
              - match:
                  prefix: "/service/colors"
                route:
                  cluster: mycluster
          http_filters:
          - name: envoy.filters.http.router

  clusters:
  - name: red_delay
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: red_delay
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: service_red
                port_value: 80

  - name: blue_abort
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: blue_abort
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: service_blue
                port_value: 80

  - name: green
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: green
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: service_green
                port_value: 80

  - name: mycluster
    connect_timeout: 0.25s
    type: STRICT_DNS
    lb_policy: ROUND_ROBIN
    load_assignment:
      cluster_name: mycluster
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: colored
                port_value: 80

# send-requests.sh
[root@k8s-harbor01 fault-injection]# cat send-requests.sh
#!/bin/bash
#
if [ $# -ne 2 ]
then
    echo "USAGE: $0 <URL> <COUNT>"
    exit 1;
fi

URL=$1
COUNT=$2
c=1
#interval="0.2"

while [[ ${c} -le ${COUNT} ]];
do
  #echo "Sending GET request: ${URL}"
  curl -o /dev/null -w '%{http_code}\n' -s ${URL} &
  (( c++ ))
#  sleep $interval
done

wait

# service-envoy-fault-injection-abort.yaml
[root@k8s-harbor01 fault-injection]# cat service-envoy-fault-injection-abort.yaml
admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

layered_runtime:
  layers:
  - name: admin
    admin_layer: {}

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: local_service
          http_filters:
          - name: envoy.filters.http.fault
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
              max_active_faults: 100
              abort:
                http_status: 503
                percentage:
                  numerator: 10
                  denominator: HUNDRED
          - name: envoy.filters.http.router
            typed_config: {}

  clusters:
  - name: local_service
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: local_service
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 8080

# service-envoy-fault-injection-delay.yaml
[root@k8s-harbor01 fault-injection]# cat service-envoy-fault-injection-delay.yaml
admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

layered_runtime:
  layers:
  - name: admin
    admin_layer: {}

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: local_service
          http_filters:
          - name: envoy.filters.http.fault
            typed_config:
              "@type": type.googleapis.com/envoy.extensions.filters.http.fault.v3.HTTPFault
              max_active_faults: 100
              delay:
                fixed_delay: 10s
                percentage:
                  numerator: 10
                  denominator: HUNDRED
          - name: envoy.filters.http.router
            typed_config: {}

  clusters:
  - name: local_service
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: local_service
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 8080

# service-envoy.yaml
[root@k8s-harbor01 fault-injection]# cat service-envoy.yaml
admin:
  profile_path: /tmp/envoy.prof
  access_log_path: /tmp/admin_access.log
  address:
    socket_address:
       address: 0.0.0.0
       port_value: 9901

layered_runtime:
  layers:
  - name: admin
    admin_layer: {}

static_resources:
  listeners:
  - name: listener_0
    address:
      socket_address: { address: 0.0.0.0, port_value: 80 }
    filter_chains:
    - filters:
      - name: envoy.filters.network.http_connection_manager
        typed_config:
          "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
          stat_prefix: ingress_http
          codec_type: AUTO
          route_config:
            name: local_route
            virtual_hosts:
            - name: service
              domains: ["*"]
              routes:
              - match:
                  prefix: "/"
                route:
                  cluster: local_service
          http_filters:
          - name: envoy.filters.http.router

  clusters:
  - name: local_service
    connect_timeout: 0.25s
    type: strict_dns
    lb_policy: round_robin
    load_assignment:
      cluster_name: local_service
      endpoints:
      - lb_endpoints:
        - endpoint:
            address:
              socket_address:
                address: 127.0.0.1
                port_value: 8080

1.4.4.2 启动容器
[root@k8s-harbor01 fault-injection]# docker-compose up -d

[root@k8s-harbor01 fault-injection]# docker-compose ps
             Name                           Command               State              Ports
-----------------------------------------------------------------------------------------------------
faultinjection_envoy_1           /docker-entrypoint.sh envo ...   Up      10000/tcp, 80/tcp, 9901/tcp
faultinjection_service_blue_1    /bin/sh -c /usr/local/bin/ ...   Up      10000/tcp, 80/tcp
faultinjection_service_green_1   /bin/sh -c /usr/local/bin/ ...   Up      10000/tcp, 80/tcp
faultinjection_service_red_1     /bin/sh -c /usr/local/bin/ ...   Up      10000/tcp, 80/tcp
1.4.4.3 测试注入的delay(延迟)故障
 # 反复向/service/red发起多次请求,被注入延迟的请求,会有较长的响应时长;
 # 这里的故障注入是10%的请求,所以要多请求几次,才能看见效果
 [root@k8s-harbor01 fault-injection]# curl -w"@curl_format.txt" -o /dev/null -s "http://172.31.62.10/service/red"

在这里插入图片描述

1.4.4.4 测试注入的abort(响应)故障

注入该故障的目的是为了检测下游服务是否具备处理该类型故障的功能,如超时机制、熔断机制等。

 # 反复向/service/blue发起多次请求,被注入中断的请求,则响应以503代码;
 [root@k8s-harbor01 fault-injection]# curl -o /dev/null -w '%{http_code}\n' -s "http://172.31.62.10/service/blue"

在这里插入图片描述

1.4.4.5 请求无注入的接口
[root@k8s-harbor01 fault-injection]# curl -o /dev/null -w '%{http_code}\n' -s "http://172.31.62.10/service/green"

在这里插入图片描述

1.4.4.6 清理环境
[root@k8s-harbor01 fault-injection]# docker-compose  down

[root@k8s-harbor01 fault-injection]# docker ps -a
CONTAINER ID   IMAGE     COMMAND   CREATED   STATUS    PORTS     NAMES

2. 超时、重试

2.1 局部故障处理机制

(1)retry(重试机制)
分布式环境中对远程资源和服务的调用,可能会由于瞬态故障(短时间内可自行恢复的故障)而失败,一般情况下,重试机制可解决此类问题。
- 常见的瞬态故障有网络连接速度慢、超时、资源过量使用或暂时不可用等。

(2)timeout
此外,也存在因意外事件而导致故障,并且可能需要较长的时间才能得以恢复;
- 此类故障的严重性范围涵盖,从部分连接中断到服务完全失败;
- 连续重试和长时间的等待对该类场景都没有太大意义。
- 应用程序应迅速接受该操作已失败,并主动地应对该失败,比如降级,非核心功能可以使用降级的方式,让程序有缺陷的运行。
- 可以将调用服务的操作配置为实施“超时”,若该服务在超时时长内未能响应,则以失败消息响应。

(3)circuit breaker(熔断,断路器)
还有,若服务非常繁忙,则系统某一部分的故障可能会导致级联故障(就是A调用B,B已经挂了,此时流量就会反压到A,把A也弄死);
对此,简单的超时策略可能导致对同一操作的许多并发请求被阻止,直到超时时长耗尽为止;
这些被阻止的请求可能包含关键的系统资源,例如内存、线程和数据库连接等;
- 这类资源的耗尽,可能导致需要使用相同资源的系统其他可能不相关的部分出现故障;
- 于是,此时最好立即使操作失败,并且仅在可能成功的情况下才尝试调用服务;

2.2 请求重试

2.2.1 请求重试介绍

分布式应用环境中的瞬态故障并不鲜见。
常见的故障包括与组件和服务的网络连接的暂时丢失、服务暂时不可用或服务繁忙时发生的超时等。
这类故障通常能自我纠正,并且如果在适当的延迟后,重复此前触发了故障的请求操作,则可能会成功。
通过透明地重试失败的操作,使应用程序在尝试连接到服务或网络资源时能够处理瞬态故障,可以显著提高应用程序的稳定性;

在这里插入图片描述

2.2.2 常见的瞬态处理(重试)策略

常见的瞬态处理策略有如下三个:
(1)重试
对于暂时性或不常见类型的故障,反复请求通常可以获得正确结果;

(2)延迟重试
若故障是由较常见的连接故障或繁忙故障引起,通常需要一些时间纠正连接问题或清除积压工作,应用程序则应等待适当的时间,然后重试请求;

(3)取消
对于并非暂时性故障,或即便反复请求也不太可能成功的故障,则应用程序应取消该操作并报告异常;

2.2.3 请求重试注意事项

(1)重试策略需要匹配应用程序的业务需求和故障的性质,对于某些非关键操作,最好是快速失败,而不是重试几次并影响应用程序的吞吐量。
- 对于交互式的Web应用程序,在较短的延迟后进行少量重试,而后向用户显示适当的消息,例如“请稍后重试”;
- 对于批处理应用,增加重试次数可能会更合适,但重试次数之间的延迟应成倍或指数级增加;

(2)若大量重试后请求仍然失败,最好防止进一步的请求进入同一服务,并立即报告失败。
- 在一定的过期时长后,设定服务暂时允许一个或多个请求通过,以查看它们是否成功,这是断路器的功能;

(3)还需要考虑操作幂等与否。
- 对于幂等性操作,重试本质上是安全的;
- 否则,重试可能导致该操作被执行多次,并产生意外的副作用;

(4)请求可能会由于多种原因而失败,它们可能分别会引发不同的异常,重试策略应根据异常的类型,来调整两次重试之间的时间间隔。
- 有些异常可能是迅速可解决的故障;
- 有些异常则可能会持续更长时间;

(5)确保所有重试代码已针对各种故障情况进行了全面测试,以检查它们是否不会严重影响应用程序的性能或可靠性,是否对服务和资源造成过多负担,是否产生竞争状况或瓶颈。

2.2.4 请求重试配置

(1)Envoy支持在虚拟主机及路由级别配置中,以及通过特定请求的标头配置重试。
- 路由级别重试的优先级高于虚拟主机级别。

(2)重试策略的相关属性包括重试次数和重试条件等。
- 最大重试次数:可重试的最大次数
· 在每次重试之间使用指数退避算法
· 单次重试操作有其超时时长
· 所有重试都包含在整个请求的超时时长之内,以避免由于大量重试而导致的超长请求时间

(3)重试条件: 是指进行重试的前提条件,例如网络故障、5xx类的响应码等,如下图:

在这里插入图片描述

2.2.5 HTTP请求重试条件(route.RetryPolicy)

(1)重试条件1(同x-envoy-retry-on标头)
- 5xx:上游主机返回5xx响应码,或者根本没有响应(如断开/重置/读取超时),这个时候进行重试;
- gateway-error:网关错误,类似于5xx策略,但仅为502、503或504的响应码进行重试;
- connection-failure:在TCP级别与上游服务建立连接失败时进行重试;
- retriable-4xx:上游服务器返回可重试的4xx响应码时进行重试;
- refused-stream:上游服器务使用REFUSED-STREAM(和GRPC有关)错误码重置时进行重试;
- retriable-status-codes:上游服务器的响应码与重试策略或与x-envoy-retriable-status-codes标头值中定义的响应码匹配时进行重试;
- reset:上游主机完全不响应时 (disconnect/reset/read超时),Envoy将进行重试;
- retriable-headers:如果上游服务器响应报文,匹配重试策略x-envoy-retriable-header-names标头中包含的任何标头,则Envoy将尝试重试;
- envoy-ratelimited:标头中存在x-envoy-ratelimited时进行重试;

(2)重试条件2:grpc链接专用(同x-envoy-retry-grpc-on标头)
- cancelled:gRPC应答标头中的状态码是“cancelled”时进行重试;
- deadline-exceeded:gRPC应答标头中的状态码是“deadline-exceeded”时进行重试;
- internal:gRPC应答标头中的状态码是“internal”时进行重试;
- resource-exhausted:gRPC应答标头中的状态码是“resource-exhausted”时进行重试;
- unavailable:gRPC应答标头中的状态码是”unavailable“时进行重试;

(3)默认情况下,Envoy不会进行任何类型的重试操作,除非明确定义。

2.2.6 重试和超时机制配置示例

第一个路由使用了重试策略,重试条件为”5xx“,且最大重试次数为3;

第二个路由使用了超时机制,超时时长为10s;

在这里插入图片描述

2.2.7 重试插件及相关配置

(1)重试操作会触发重新选择目标主机
- 重试期间选择主机与首次处理请求时选择主机的方式相同,具体的选择行为由调度策略决定; # 如果希望重试的请求也调度到原来的机器(也就是首次请求),需要进行额外配置
- 重试插件为用户提供了配置重试期间重新选择主机的方式;

(2)重试插件可配置的主机选择方式可分为两类,且它们可以组合使用
a. Host Predicates(断言): 用于拒绝重试选择一个主机的断言,任何主机匹配断言列表中的任何断言时将会被拒绝,并导致重试进行主机选择,有以下两种选项;
- envoy.retry_host_predicates.previous_hosts:跟踪以前尝试过的主机,并拒绝已经尝试过的主机;
- envoy.retry_host_predicates.omit_canary_hosts:拒绝任何标记为Canarv的主机,其标记配置在端点的过滤器过滤的元数据中;

b. Prioritv Predicates:用于调整重试尝试选择优先级时使用的优先级负载,此类断言仅能指定一个;
- envoy.tety_priority,previous_priorities: 跟踪先前尝试的优先级,并据此调整优先级负载以便在后续的重试尝试中将其它优先级作为目标;

主机选择会持续进行到配置的谓词接受主机或达到可配置的最大尝试次数为止,下面是配置示例
retry_policy:
  retry_host_predicate:
  - name: envoy.retry_host_predicates.previous_hosts # 重试期间,不会在去连接之前已经重试过的主机
    host_selection_retry_max_attempts: 3
  retry_priority:
    name: envoy.retry_priorities.previous_priorities
	config:
      update_frequency:2

3. CORS跨域

(1)跨域资源共享(CORS)是HTTP的访问控制机制。
- 它使用额外的HTTP头来告诉浏览器,让运行在一个 origin(domain)上的web应用被准许访问来自不同源服务器上的指定的资源;
- 当一个资源从与该资源本身所在的服务器不同的域、协议或端口请求一个资源时,资源会发起一个跨域 HTTP 请求;
- 比如,站点 http://domain-a.com 的某 HTML页面通过 <img>的 src 请求 http://domain-b.com/image.jpg;网络上的许多页面都会加载来自不同域的CSS样式表,图像和脚本等资源;

(2)出于安全原因,浏览器限制从脚本内发起的跨源HTTP请求。
- 例如,XMLHttpRequest和Fetch API遵循同源策略;
- 这意味着使用这些API的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非响应报文包含了正确CORS响应头;

(3)跨域资源共享(CORS)机制,允许Web应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。

3.1 Envoy跨域资源共享(route.CorsPolicy)

(1)CORS是一种通过指定能够访问当前域的那些特定的或所有路由而来的外部域来强制对资源进行客户端访问控制的方法;
- 出于安全方面的原因,浏览器会限制从脚本发起的跨域HTTP请求;
- 因而,浏览器使用HTTP标头的存在,来确定是否允许来自不同来源的响应;

(2)Envoy的cors过滤器用于许可Web应用服务器进行跨域访问控制;
- 通过在HTTP标头中追加一些额外的信息,来通知浏览器允许跨域访问;
- 在虚拟主机或路由级别可配置的CORS策略相关控制参数如下;

cors:
  "allow_origin": []  # 允许共享的资源列表,*表示所有;
  "allow_origin_regex": [] # 正则表达式模式表示的允许共享的资源
  "allow_methods": "..." # 允许资源访问时使用的HTTP方法列表,内容将被序列化到access-control-allow-methods标头;
  "allow_headers": "..." # 允许在请求资源时使用HTTP标头列表,内容将被序列化到access-control-allow-headers标头;
  "expose_headers": "..." # 浏览器可访问的HTTP标头白名单,内容将被序列化到access-control-expose-headers标头;
  "max_age": "..." # 请求的缓存时长,内容将被序列化到access-control-max-age标头;
  "allow_credentials": "{...}" # 布尔型值,是否允许服务调用方法使用凭据发起实际请求;
  "enabled": "{...}" # 布尔型值,是否启用CORS,默认为启用;此参数即将弃用,并由filter_enabled取代;
  "filter_enabled": "{...}" # 是否启用CORS过滤器,若启用,此处需要定义启用此过滤器的请求百分比,默认为100/HUNDRED;
  default_value:
    numerator: ..
    denominator: ...
  runtime_key: ...
  "shadow_enabled": "{...}" # 是否仅在阴影模式下启用过器的请求的百分比,若启用,其默认值为100/HUNDRED;若启用,它将评估请求的来源,以确定其是否有效,但不强制执行任何策略;
  #若同时启用了filter_enabled和shadow_enabled,则filter_enabled标志优先;

(3)CORS过滤器支持两种运行时设定;
a. filter_enabled: 在请求上启用过滤器的百分比,默认为100/HUNDRED; # 该方式就表示策略是完全生效的。
- 设置filter_enabled参数的runtime_key的值,可在运行时启用或禁用CROS过滤器;

b. shadowenabled: 于影子模式下在请求上启用CORS过滤器的百分比,默认值为0;用于评估请求的Origin以确定它是否有效,但并不会强制任何策略;
- 设置shadow_enabled参数的runtime_key的值可在运行时启用或禁用CROS过滤器;

(4)Envoy的cors机制需要按如下方式配置:
a. 在过滤器列表中定义cors过滤器;
b. 在虚拟主机或路由中配置cors策略;
- 禁用: 禁用CORS
- 启用: 启用CORS,且允许的请求者为*
- 受限: 启用CORS,且允许的请求者需要自定义

3.2 CORS配置示例

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值