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解决前端跨域问题小结”的内容,你了解清楚吗?希望对你有所帮助,任何问题可以给我留言,让我们下期再见吧。













