当一个客户端去访问另一个不同域名或者同域名不同端口的服务时,就会发出跨域请求。如果此时该服务不允许其进行跨域资源访问,就会因为跨域问题而导致访问失败。跨源域资源共享CORS(Cross-Origin Resource Sharing)允许Web应用服务器进行跨域访问控制。本文介绍如何在ASM的Virtualservice中配置corsPolicy,实现跨域访问。
跨源域资源共享CORS介绍
浏览器会限制页面脚本内发起的跨源HTTP请求以提高安全性,对于需要跨域访问的场景,ASM提供了跨源域资源共享CORS功能。跨域资源共享CORS是一种基于HTTP头的机制,该机制允许服务器标示除了它自己以外的其它域,协议和端口,使得浏览器可以访问加载这些资源。
跨域资源共享CORS的验证机制分两种模式:简单请求和预先请求。
简单请求模式:
浏览器直接发送跨域请求,并在请求头中携带Origin的头,表明这是一个跨域的请求。服务器端接到请求后,会根据自己的跨域规则,通过Access-Control-Allow-Origin和Access-Control-Allow-Methods响应头来返回验证结果。
预先请求模式:
浏览器会先发送Preflighted requests(预先验证请求),Preflighted requests是一个OPTION请求,用于询问要被跨域访问的服务器,是否允许当前域名下的页面发送跨域的请求。在得到服务器的跨域授权后才能发送真正的HTTP请求。
OPTIONS请求头部中会包含以下头部:Origin、Access-Control-Request-Method、Access-Control-Request-Headers。服务器收到OPTIONS请求后,设置Access-Control-Allow-Origin、Access-Control-Allow-Method、Access-Control-Allow-Headers、Access-Control-Max-Age头部与浏览器沟通来判断是否允许这个请求。如果Preflighted requests验证通过,浏览器才会发送真正的跨域请求。
当请求同时满足下面三个条件时,CORS验证机制会使用简单请求模式进行处理,否则CORS验证机制会使用预先请求模式进行处理。
请求方法是下列之一:
GET、HEAD、POST
请求头中的Content-Type请求头的值是下列之一:
text/plain、application/x-www-form-urlencoded、multipart/form-data
Fetch规范定义了CORS安全头的集合,安全头的集合是下列之一:
Accept、Accept-Language、Content-Language、Content-Type(需要注意额外的限制)
在VirtualService中配置corsPolicy
整个CORS通信过程都是浏览器自动完成,您需要在对应服务的VirtualService中添加corsPolicy
字段,使服务允许跨域请求,从而实现跨域通信。
参数 | 说明 |
allowOrigins | 允许请求服务的来源,允许带哪些Origin地址的请求,支持regex匹配。对于不需要携带身份凭证的请求,服务器可以指定该字段的值为通配符,表示允许来自所有域的请求。 |
allowMethods | 允许请求服务的方法,实际请求所允许使用的HTTP方法。 |
allowHeaders | 允许请求服务的标头,用于预检请求的响应。其指明了实际请求中允许携带的首部字段。 |
exposeHeaders | 公开请求服务的标头,让服务器把允许浏览器访问的头放入白名单。 |
maxAge | 最大浏览器缓存时间,指定了浏览器能够缓存preflight请求结果的时间。 |
allowCredentials | 允许请求服务的凭证,符合要求的凭证才能请求服务。 |
跨域访问最佳实践
准备工作
已添加集群到ASM实例。具体操作,请参见添加集群到ASM实例。
已创建default和foo命名空间,并为命名空间开启自动注入。具体操作,请参见管理全局命名空间。
步骤一:部署应用
部署后端应用。
使用以下内容,创建details.yaml 文件。
执行以下命令,在default命名空间部署details应用。
kubectl apply -f details.yaml -n default
部署前端应用。
使用以下内容,创建istio-cors-demo.yaml 文件。
执行以下命令,在foo命名空间部署istio-cors-demo应用。
kubectl apply -f istio-cors-demo.yaml -n foo
步骤二:创建ASM网关
登录ASM控制台,在左侧导航栏,选择 。
在网格管理页面,单击目标实例名称,然后在左侧导航栏,选择 。
在入口网关页面,单击创建。
在创建页面,设置名称为ingressgateway,选择部署集群,设置负载均衡CLB类型为公网访问,在新建负载均衡CLB下选择负载均衡规格,其他参数采用默认设置,然后单击创建。
步骤三:创建路由规则
创建后端应用的路由规则。
创建网关规则,绑定details应用和ingressgateway网关。
登录ASM控制台,在左侧导航栏,选择 。
在网格管理页面,单击目标实例名称,然后在左侧导航栏,选择
。在网关规则页面,单击使用YAML创建。
在创建页面,设置命名空间为default,选择任意场景模版,将YAML文本框中的内容替换为以下内容,然后单击创建。
apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: bookinfo-gateway namespace: default spec: selector: istio: ingressgateway servers: - hosts: - '*' port: name: http number: 80 protocol: HTTP
创建虚拟服务。
在网格详情页面左侧导航栏选择
,然后在右侧页面单击使用YAML创建。在创建页面,设置命名空间为default,选择任意场景模版,将YAML文本框中的内容替换为以下内容,然后单击创建。
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: bookinfo namespace: default spec: gateways: - bookinfo-gateway hosts: - '*' http: - match: - uri: prefix: /details route: - destination: host: details port: number: 9080
访问后端应用。
获取ingressgateway网关的IP地址,具体操作,请参见创建入口网关。
在浏览器地址栏中输入http://<ingressgateway网关的IP>/details/2 。
返回以上页面,表明访问后端应用details成功。
创建前端应用的路由规则。
创建网关规则。
创建网关规则,绑定istio-cors-demo应用和ingressgateway2网关。
在网格详情页面左侧导航栏,选择
,然后在网关规则页面,单击使用YAML创建。在创建页面,设置命名空间为foo,选择任意场景模版,将YAML文本框中的内容替换为以下内容,然后单击创建。
apiVersion: networking.istio.io/v1beta1 kind: Gateway metadata: name: istio-cors-demo-gateway namespace: foo spec: selector: istio: ingressgateway2 servers: - hosts: - '*' port: name: http number: 80 protocol: HTTP
创建虚拟服务。
在网格详情页面左侧导航栏,选择
,然后在虚拟服务页面,单击使用YAML创建。在创建页面设置命名空间为foo,选择任意场景模版,将YAML文本框中的内容替换为以下内容,然后单击创建。
apiVersion: networking.istio.io/v1beta1 kind: VirtualService metadata: name: istio-cors-demo namespace: foo spec: gateways: - istio-cors-demo-gateway hosts: - '*' http: - route: - destination: host: istio-cors-demo port: number: 8000
使用前端应用访问后端应用。
获取ingressgateway2网关的IP地址,具体操作,请参见创建入口网关。
在谷歌浏览器地址栏,输入http://<ingressgateway2网关的IP地址>。
在URL文本框,输入http://<ingressgateway网关的IP地址>/details/2 ,单击Send。
在谷歌浏览器右上角,单击图标,选择 。
由于前端istio-cors-demo应用访问后端details应用需要跨域,访问会失败,因此出现以上报错。
步骤四:配置跨域访问
登录ASM控制台,在左侧导航栏,选择 。
在网格管理页面,单击目标实例名称,然后在左侧导航栏,选择 。
在虚拟服务页面,单击bookinfo右侧操作列下的查看YAML。
在编辑对话框的http参数下,添加以下跨域配置,然后单击确定。
- corsPolicy: allowCredentials: false allowMethods: - POST - GET allowOrigins: - prefix: 'http://<ingressgateway2网关的IP>' maxAge: 24h
步骤五:验证跨域访问是否成功
在谷歌浏览器地址栏,输入http://<ingressgateway2网关的IP地址>。
在URL文本框,输入http://<ingressgateway网关的IP地址>/details/2 ,单击Send。
返回以上页面,表明前端istio-cors-demo应用访问后端details应用成功,跨域访问成功。