最近要重构一个基于spring boot的后端API服务,需要再本地测试。在本地测试时,运行在本地的前端页面发送一个ajax请求访问后端API,然后浏览器报错blocked CORS policy。

Access to XMLHttpRequest at 'http://127.0.0.1:1234/api/' from origin 'http://dev.couchbase.cloud.qiyi.domain' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

最后的解决方法很简单,只需要在相应的Controller上加一个注解@CrossOrigin就可以了,也可以将注解加到相应的方法上面。

为什么有些时候调用服务器的接口时没有发生这个报错?

原因:浏览器发送ajax请求必须是同源的,也就是浏览器访问服务器接口需要考虑同源,而服务器与服务器之间访问接口是不需要考虑同源的。

(一)同源策略(SOP策略)

同源策略(Same-Origin-Policy):URL由协议、域名、端口和路径组成,如果两个URL的协议、域名和端口相同,则表示他们同源。相反,只要协议,域名,端口有任何一个的不同,就被当作是跨域。

浏览器采用同源策略,禁止页面加载或执行与自身来源不同的域的任何文档或脚本,换句话说浏览器禁止的是来自不同源的"document"或脚本。在一个http请求中,http头部Referer或Origin字段标识了当前域名,Host字段标识了此时请求的域名。因此我们在当前的js页面,通过ajax请求第三方的数据,就会出现浏览器的跨域问题。

(二)跨域解决方法

1. 使用CORS策略

CORS策略:跨域资源共享(Corss Origin Resource Sharing)通过服务器增加一个特殊的Header[Access-Control-Allow-Origin]来告知客户端跨域的限制,如果浏览器支持CORS的话,当判断Origin通过的话,就会允许请求。使用这个Header返回被允许请求跨域请求的来源域,例如网站duelist.cn设置了下面的Header

Access-Control-Allow-Origin: http://smdcn.net

这样设置之后,通过http://smdcn.net下的页面对于duelist.cn进行ajax请求就会被允许,而其他网站对duelist.cn依旧会被阻拦,通过这种方式网站拥有者可以自己对此进行限制。当然,如果不想限制来源,可以通过来允许任何站点对该资源进行跨域请求

Access-Control-Allow-Origin: *

CORS规范中常见的头信息:

常见的头信息包括:

  Request Headers:

  Origin、Access-Control-Request-Method、Access-Control-Request-Headers

  Response Headers:

  . 允许向该服务器提交请求的URI

  Access-Control-Allow-Origin: <origin> | *

  . 浏览器允许访问的服务器的头信息的白名单

  Access-Control-Expose-Headers: ..., ...

  . 请求有效期(单位:秒):

  Access-Control-Max-Age: <seconds>

  . 允许的请求方法:

  Access-Control-Allow-Methods

  . 实际的请求中,可以使用的自定义HTTP请求头

  Access-Control-Allow-Headers

  . 告知客户端,当请求XHR的withCredientials属性是true的时候,响应是否可以被得到。(从而使得下一次请求时,上一次的Cookies可以随着请求发送)

  Access-Control-Allow-Credentials:

在传统的Spring MVC中的使用方法:(网上较多资料都是这种方法)

import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component; @Component
public class SimpleCORSFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with");
chain.doFilter(req, res);
} public void init(FilterConfig filterConfig) {} public void destroy() {} }
<filter>
<filter-name>cors</filter-name>
<filter-class>com.app.filter.SimpleCORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>cors</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

在Spring boot中的使用方法就是添加注解@CrossOrigin

向@RequestMapping注解的Controller方法处添加一个@CrossOrigin注解:

@RestController
@RequestMapping("/account")
public class AccountController { @CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
} @DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}

为整个controller启用@CrossOrigin:

@CrossOrigin(origins = "http://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController { @GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
// ...
} @DeleteMapping("/{id}")
public void remove(@PathVariable Long id) {
// ...
}
}

其中@CrossOrigin中的2个参数:

origins  : 允许可访问的域列表

maxAge:准备响应前的缓存持续的最大时间(以秒为单位)。

2. 使用jsonp

jsonp解决跨域问题的原理是,浏览器的script标签是不受同源策略限制的,我们可以在script标签中访问任何域名下的资源文件。利用这一特性,用script标签从服务器中请求数据,同时服务器返回一个带有方法和数据的js代码,请求完成,调用本地的js方法,来完成数据的处理。

不推荐使用jsonp,首先jsonp是一种非官方的方法,而且这种方法只支持GET方法,不如POST方法安全;而且一般前后端分离最通用的方法是返回统一的json格式。

3. 服务器代理

这种方式运用的就是服务器的反向代理技术,控制客户端和服务器的访问都从代理服务器经过,比如用nginx作为服务器代理,在nginx上配置客户端和第三方服务的反向代理,这样就可保证客户端、第三方是同源的了,同一个源,都来自代理服务器。

前端页面调用Spring boot接口发生的跨域问题的更多相关文章

  1. Spring Boot 通过CORS实现跨域

    同源策略 很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略. 同源策略是由 Netscape 提出的一个著名的安全策略,它是浏览器最核心也 ...

  2. express搭建后端请求路由,前端进行访问对应的接口 后端解决跨域

    代码在 ==>E:\nodes实战\myserve\testserve 1 express搭建后端请求路由,前端进行访问对应的接口 1) 创建项目目录 express 项目名 -e 然后按照提示 ...

  3. Spring Boot+AngularJS中因为跨域导致Session丢失

    http://blog.csdn.net/dalangzhonghangxing/article/details/52446821 如果还在为跨域问题烦恼,请查看博主的 解决angular+sprin ...

  4. spring boot 接口返回值封装

    Spring Boot 集成教程 Spring Boot 介绍 Spring Boot 开发环境搭建(Eclipse) Spring Boot Hello World (restful接口)例子 sp ...

  5. Spring Boot全局支持CORS(跨源请求)

    import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet. ...

  6. 关于 Spring Security OAuth2 中 CORS 跨域问题

    CORS 是一个 W3C 标准,全称是”跨域资源共享”(Cross-origin resource sharing).它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了 AJA ...

  7. Spring Boot 接口幂等插件使用

    幂等概述 幂等性原本是数学上的概念,即使公式:f(x)=f(f(x)) 能够成立的数学性质.用在编程领域,则意为对同一个系统,使用同样的条件,一次请求和重复的多次请求对系统资源的影响是一致的. 幂等性 ...

  8. spring boot:接口站增加api版本号后的安全增强(spring boot 2.3.3)

    一,接口站增加api版本号后需要做安全保障? 1,如果有接口需要登录后才能访问的, 需要用spring security增加授权 2,接口站需要增加api版本号的检验,必须是系统中定义的版本号才能访问 ...

  9. 一个简单的Webservice的demo(中)_前端页面调用

    首先新建项目,这里有两种调用方式,为了能方便理解,新建页面WebserviceTest如下图: 先引用写好的服务,这里用上次写好的服务.见上次写的一个简单的Webservice的demo,简单模拟服务 ...

随机推荐

  1. 6.1-uC/OS-III软件定时器

    1.软件定时器是 uC/OS 操作系统的一个内核对象,软件定时器是基于时钟节拍和系统管理创建的软件性定时器,理论上可以创建无限多个,但精准度肯定比硬件定时稍逊一筹. 2.软件定时器启动之后是由软件定时 ...

  2. 如何在一个电脑上使用两个github账号

    问题描述:公司电脑上默认使用的是公司的github账号,如果希望写一些代码放到个人的github账号上,就需要配置让一个电脑上可以使用两个github账号 原理:管理两个SSH key 1.生成两个S ...

  3. Qt中信号(signal)和槽(slot)的几种关联方法

    声明,个人总结,不一定正确! 1.最常见的,使用connect语句.比如:connect(btnSend,SIGNAL(clicked()),this,SLOT(clear()); 2.在 .ui设计 ...

  4. 转换编码utf-8

    用这个enca -x utf-8 * 或者是 filename,还有别的方法,参见:https://blog.csdn.net/a280606790/article/details/8504133 我 ...

  5. gitlab重置root的密码

    环境:gitlab 忘记了root密码,无法登陆gitlab 解决: gitlab-ctl start 保证gitlab处于启动状态,&保证redis处于启动状态 gitlab-rails c ...

  6. Delphi7使用一段时间后抽风提示注册

    今天在单位用电脑接自己的移动硬盘,一打开资源管理器就卡死,删除硬盘总是提示用程序在使用,反复试了几次,老样子.很是窝火.干脆直接关机电脑,桌面上还有开着的Delphi编译器,重新开机!开机后一打开编译 ...

  7. 2017-2018-1 20155228 《数学建模》 MatlabR2017a安装教程

    2017-2018-1 20155228MatlabR2017a安装教程 原版软件和破解补丁的下载 原版软件和破解补丁的下载链接 需要关注微信公众号才能获取下载密码,照办就是了,为了学习嘛哈哈哈 有三 ...

  8. GCD(IV)

    死锁:2个任务相互等待造成的. - (void) GCD { NSLog(@"begin"); dispatch_queue_t queue = dispatch_queue_cr ...

  9. 基于注解的Spring事务配置

    spring采用@Transactional注解进行事务申明,@Transactional既可以在方法上申明,也可以在类上申明,方法申明优先于类申明. 1.pom配置 包括spring核心包引入以及s ...

  10. 杂谈迁移tomcat项目到docker,以及遇到的问题

    1.迁移tomcat项目异常简单,下一个tomcat的container,然后直接把webapps放进去就行了. #tomcat版本随原始项目版本而变,具体版本列表查看:https://hub.doc ...