阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

处理CORS

24次阅读
没有评论

共计 2383 个字符,预计需要花费 6 分钟才能阅读完成。

在开发 REST 应用时,很多时候,是通过页面的 JavaScript 和后端的 REST API 交互。

在 JavaScript 与 REST 交互的时候,有很多安全限制。默认情况下,浏览器按同源策略放行 JavaScript 调用 API,即:

  • 如果 A 站在域名 a.com 页面的 JavaScript 调用 A 站自己的 API 时,没有问题;
  • 如果 A 站在域名 a.com 页面的 JavaScript 调用 B 站 b.com 的 API 时,将被浏览器拒绝访问,因为不满足同源策略。

同源要求域名要完全相同(a.comwww.a.com 不同),协议要相同(httphttps 不同),端口要相同。

那么,在域名 a.com 页面的 JavaScript 要调用 B 站 b.com 的 API 时,还有没有办法?

办法是有的,那就是 CORS,全称 Cross-Origin Resource Sharing,是 HTML5 规范定义的如何跨域访问资源。如果 A 站的 JavaScript 访问 B 站 API 的时候,B 站能够返回响应头Access-Control-Allow-Origin: http://a.com,那么,浏览器就允许 A 站的 JavaScript 访问 B 站的 API。

注意到跨域访问能否成功,取决于 B 站是否愿意给 A 站返回一个正确的 Access-Control-Allow-Origin 响应头,所以决定权永远在提供 API 的服务方手中。

关于 CORS 的详细信息可以参考 MDN 文档,这里不再详述。

使用 Spring 的 @RestController 开发 REST 应用时,同样会面对跨域问题。如果我们允许指定的网站通过页面 JavaScript 访问这些 REST API,就必须正确地设置 CORS。

有好几种方法设置 CORS,我们来一一介绍。

使用 @CrossOrigin

第一种方法是使用 @CrossOrigin 注解,可以在 @RestController 的 class 级别或方法级别定义一个@CrossOrigin,例如:

@CrossOrigin(origins = "http://local.liaoxuefeng.com:8080")
@RestController
@RequestMapping("/api")
public class ApiController {...}

上述定义在 ApiController 处的 @CrossOrigin 指定了只允许来自 local.liaoxuefeng.com 跨域访问,允许多个域访问需要写成数组形式,例如 origins = {"http://a.com", "https://www.b.com"})。如果要允许任何域访问,写成origins = "*" 即可。

如果有多个 REST Controller 都需要使用 CORS,那么,每个 Controller 都必须标注 @CrossOrigin 注解。

使用 CorsRegistry

第二种方法是在 WebMvcConfigurer 中定义一个全局 CORS 配置,下面是一个示例:

@Bean
WebMvcConfigurer createWebMvcConfigurer() {return new WebMvcConfigurer() {@Override
        public void addCorsMappings(CorsRegistry registry) {registry.addMapping("/api/**")
                    .allowedOrigins("http://local.liaoxuefeng.com:8080")
                    .allowedMethods("GET", "POST")
                    .maxAge(3600);
            // 可以继续添加其他 URL 规则:
            // registry.addMapping("/rest/v2/**")...
        }
    };
}

这种方式可以创建一个全局 CORS 配置,如果仔细地设计 URL 结构,那么可以一目了然地看到各个 URL 的 CORS 规则,推荐使用这种方式配置 CORS。

使用 CorsFilter

第三种方法是使用 Spring 提供的CorsFilter,我们在集成 Filter 中详细介绍了将 Spring 容器内置的 Bean 暴露为 Servlet 容器的 Filter 的方法,由于这种配置方式需要修改web.xml,也比较繁琐,所以推荐使用第二种方式。

测试

当我们配置好 CORS 后,可以在浏览器中测试一下规则是否生效。

我们先用 http://localhost:8080 在 Chrome 浏览器中打开首页,然后打开 Chrome 的开发者工具,切换到 Console,输入一个 JavaScript 语句来跨域访问 API:

$.getJSON("http://local.liaoxuefeng.com:8080/api/users", (data) => console.log(JSON.stringify(data)));

上述源站的域是 http://localhost:8080,跨域访问的是http://local.liaoxuefeng.com:8080,因为配置的 CORS 不允许localhost 访问,所以不出意外地得到一个错误:

处理 CORS

浏览题打印了错误原因就是been blocked by CORS policy

我们再用 http://local.liaoxuefeng.com:8080 在 Chrome 浏览器中打开首页,在 Console 中执行 JavaScript 访问localhost

$.getJSON("http://localhost:8080/api/users", (data) => console.log(JSON.stringify(data)));

因为 CORS 规则允许来自 http://local.liaoxuefeng.com:8080 的访问,因此访问成功,打印出 API 的返回值:

处理 CORS

练习

使用 CORS 控制跨域。

下载练习

小结

CORS 可以控制指定域的页面 JavaScript 能否访问 API。

正文完
星哥说事-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2024-08-05发表,共计2383字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中