JS 跨域问题

官方文档介绍

一、简介

跨域:指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript 施加的安全限制。
同源策略:是指协议,域名,端口都要相同,其中有一个不同都会产生跨域;
在这里插入图片描述
  跨源资源共享标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的 HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME(媒体类型)类型 的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨源请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP认证 相关数据)。

  CORS 请求失败会产生错误,但是为了安全,在 JavaScript 代码层面是无法获知到底具体是哪里出了问题。你只能查看浏览器的控制台以得知具体是哪里出现了错误。

二、简单请求

某些请求不会触发 CORS 预检请求。本文称这样的请求为“简单请求”,请注意,该术语并不属于 Fetch (其中定义了 CORS)规范。若请求 满足所有下述条件,则该请求可视为“简单请求”:
1、使用下列方法之一:

  • GET
  • HEAD
  • POST

2、除了被用户代理自动设置的首部字段(例如 Connection,User-Agent)和在 Fetch 规范中定义为 禁用首部名称 的其他首部,允许人为设置的字段为 Fetch 规范定义的 对 CORS 安全的首部字段集合。该集合为:

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type (需要注意额外的限制)

3、Content-Type 的值仅限于下列三者之一:

  • text/plain
  • multipart/form-data
  • application/x-www-form-urlencoded

4、请求中的任意 XMLHttpRequest 对象均没有注册任何事件监听器;XMLHttpRequest 对象可以使用 XMLHttpRequest.upload 属性访问。
5、请求中没有使用 ReadableStream 对象。

示例:
以下是浏览器发送给服务器的请求报文:

GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example

请求首部字段 Origin 表明该请求来源于 http://foo.example。

HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[XML Data]

本例中,服务端返回的 Access-Control-Allow-Origin: * 表明,该资源可以被 任意 外域访问。

Access-Control-Allow-Origin: *

使用 Origin 和 Access-Control-Allow-Origin 就能完成最简单的访问控制。如果服务端仅允许来自 https://foo.example 的访问,该首部字段的内容如下:

Access-Control-Allow-Origin: https://foo.example

备注: 当响应的是附带身份凭证的请求时,服务端 必须 明确 Access-Control-Allow-Origin
的值,而不能使用通配符“*”。

三、非简单请求

非简单请求(PUT、DELETE)等,需要先发送预检请求

与前述简单请求不同,“需预检的请求”要求必须首先使用 OPTIONS 方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

1、跨域流程:
在这里插入图片描述
2、如下是一个需要执行预检请求的 HTTP 请求:
前端Vue 项目向后端微服务发送一个登录请求

this.$http({
  url: this.$http.adornUrl('/sys/login'),
  method: 'post',
  data: this.$http.adornData({
    'username': this.dataForm.userName,
    'password': this.dataForm.password,
    'uuid': this.dataForm.uuid,
    'captcha': this.dataForm.captcha
  })
})

3、如果不配置跨域解决方案,会出现以下错误
在这里插入图片描述
3、解决跨域
1)、使用nginx部署为同一域:通过访问Nginx代理到其他服务,这样就保证了协议、端口、域名都相同,就不会出现跨域的问题了。
2)、配置当次请求允许跨域
添加响应头

  • Access-Control-Allow-Origin:支持哪些来源的请求跨域
  • Access-Control-Allow-Methods:支持哪些方法跨域
  • Access-Control-Allow-Credentials:跨域请求默认不包含cookie,设置为true可以包含 cookie
  • Access-Control-Expose-Headers:跨域请求暴露的字段
    CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段: Cache-Control、Content-Language、Content-Type、Expires、Last-Modified、Pragma。如 果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。
  • Access-Control-Max-Age:表明该响应的有效时间为多少秒。在有效时间内,浏览器无 须为同一请求再次发起预检请求。请注意,浏览器自身维护了一个最大有效时间,如果 该首部字段的值超过了最大有效时间,将不会生效。

一般在接受到预检请求时,向响应头里面配置允许跨域,可以在每个微服务内配置,也可以统一在网关 Gateway 配置,网关统一配置如下:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;

@Configuration
public class MyCorsConfiguration {

    @Bean
    public CorsWebFilter corsWebFilter(){
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();

        CorsConfiguration corsConfiguration = new CorsConfiguration();

        // 1、配置跨域
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.setAllowCredentials(true);

        source.registerCorsConfiguration("/**", corsConfiguration);

        return new CorsWebFilter(source);
    }
}

4、发送的预检请求如下,已经通过了检查,允许跨域了
在这里插入图片描述
5、响应头返回的中允许跨域配置如下:
在这里插入图片描述
6、此时POST请求就可以正常访问了
在这里插入图片描述

 

posted @ 2022-04-12 07:13  FireCode  阅读(99)  评论(0编辑  收藏  举报