SpringBoot JSONP解决前端跨域问题小结
一、背景与概念
跨域问题概述
在Web开发中,跨域问题是指浏览器阻止来自不同源的请求,同源策略是浏览器的一种安全机制,它要求协议、域名和端口必须一致,否则会阻止请求,这种限制是为了保护用户免受CSRF(跨站请求伪造)等攻击。
JSONP原理
JSONP(JSON with Padding)是一种通过动态创建<script>
标签来实现跨域数据访问的方法,其基本原理是利用<script>
标签不受同源策略限制的特性,将回调函数名作为参数传递给服务器,服务器返回一段JavaScript代码,这段代码调用指定的回调函数并传递数据。
Spring Boot简介
Spring Boot是一个基于Spring框架的开源项目,旨在简化新Spring应用程序的初始搭建和开发过程,它提供了默认配置和自动化设置,使开发者能够快速构建生产级的Spring应用。
二、服务端配置
CORS配置
CORS(CrossOrigin Resource Sharing)是一种允许服务器声明哪些来源有权限访问资源的机制,Spring Boot通过配置CORS来允许跨域请求。
1.1 添加依赖
需要在项目的pom.xml
文件中添加CORS相关的依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>springbootstarterweb</artifactId> </dependency>
1.2 配置类实现
创建一个配置类,实现WebMvcConfigurer
接口,并在其中配置CORS:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") // 允许所有来源 .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的HTTP方法 .allowedHeaders("*") // 允许的头部信息 .allowCredentials(true) // 是否允许发送Cookie信息 .maxAge(3600); // 预检请求的缓存时间 } }
JSONP配置
为了支持JSONP,需要自定义一个过滤器或使用现有的解决方案,下面是一个自定义过滤器的示例:
2.1 创建JSONP过滤器
创建一个过滤器类,用于处理JSONP请求:
import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class JsonpFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException {} @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; String callback = httpRequest.getParameter("callback"); if (callback != null) { // 设置内容类型为JavaScript httpResponse.setContentType("application/javascript"); // 处理请求并生成响应 chain.doFilter(request, response); // 包装JSON数据到回调函数中 httpResponse.getWriter().write(callback + "(" + httpResponse.getContentWriter().toString() + ");"); } else { chain.doFilter(request, response); } } @Override public void destroy() {} }
2.2 注册过滤器
在配置类中注册该过滤器:
import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FilterConfig { @Bean public FilterRegistrationBean<JsonpFilter> jsonpFilter() { FilterRegistrationBean<JsonpFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new JsonpFilter()); registrationBean.addUrlPatterns("/*"); return registrationBean; } }
三、客户端实现
AJAX请求示例
在前端页面中,可以使用jQuery或其他AJAX库发送JSONP请求,以下是使用jQuery发送JSONP请求的示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF8"> <title>JSONP Example</title> <script src="https://code.jquery.com/jquery3.6.0.min.js"></script> <script type="text/javascript"> $(document).ready(function() { $.ajax({ url: "http://localhost:8080/jsonp/testJsonp", dataType: "jsonp", // 指定返回的数据类型为jsonp jsonpCallback: "localHandler", // 指定回调函数名 success: function(data) { console.log("Success:", data); }, error: function() { console.error("Error in JSONP request"); } }); }); function localHandler(data) { console.log("Callback called with data:", data); } </script> </head> <body> <h1>JSONP Example</h1> </body> </html>
JSONP请求处理流程
1、客户端发起请求:客户端通过<script>
标签发起跨域请求,并将回调函数名作为参数传递给服务器。
2、服务器处理请求:服务器接收到请求后,根据回调函数名生成相应的JavaScript代码,并将数据包裹在该代码中返回给客户端。
3、客户端执行回调:客户端接收到服务器返回的JavaScript代码后,执行其中的回调函数,从而获取到所需的数据。
4、数据处理:客户端在回调函数中处理从服务器获取的数据。
四、相关问题与解答
JSONP与CORS的区别是什么?
解答:JSONP和CORS都是解决跨域问题的常见方法,但它们有不同的工作原理和适用场景。
JSONP:主要通过动态创建<script>
标签来实现跨域请求,适用于GET请求,由于其依赖于<script>
标签的特性,存在一定的安全隐患(如被恶意网站利用)。
CORS:是一种更为现代和安全的解决方案,通过设置HTTP响应头来允许或限制特定来源的跨域请求,支持多种HTTP方法(GET、POST、PUT、DELETE等),并且可以通过预检请求来确保安全性。
2. Spring Boot如何同时支持JSON和JSONP?
解答:在Spring Boot中,可以通过配置不同的URL路径或请求参数来区分JSON和JSONP请求,可以定义两个不同的控制器方法,一个处理JSON请求,另一个处理JSONP请求:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.beans.factory.annotation.Autowired; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import java.util.HashMap; import java.util.Map; @RestController @RequestMapping("/api") public class ApiController { @GetMapping(value = "/json", produces = MediaType.APPLICATION_JSON_VALUE) public Map<String, Object> getJson() { Map<String, Object> response = new HashMap<>(); response.put("message", "This is a JSON response"); return response; } @RequestMapping(value = "/jsonp", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<String> getJsonp(@RequestParam("callback") String callback) { ObjectMapper mapper = new ObjectMapper(); ObjectNode response = mapper.createObjectNode(); response.put("message", "This is a JSONP response"); String jsonResponse = mapper.writeValueAsString(response); return ResponseEntity.ok(callback + "(" + jsonResponse + ");"); } }
上述代码中,/api/json
路径返回普通的JSON响应,而/api/jsonp
路径则返回JSONP响应,客户端可以根据需要选择不同的路径进行请求。
小伙伴们,上文介绍了“springboot jsonp解决前端跨域问题小结”的内容,你了解清楚吗?希望对你有所帮助,任何问题可以给我留言,让我们下期再见吧。