【springboot】【若依 (ruoyi)】@RestController 接口支持 JSONP

前言

  • 若依 (ruoyi): v4.3
  • springboot 2.1.1.RELEASE
  • spring 5.1.3.RELEASE
  • 360 极速浏览器 12.0.1476.0 (正式版本) (32 位)
  • jquery 3.5.0

简单来说,@RestController 接口支持 JSONP 需要对返回结果用 callback 包裹。

需求为:

  • jsonpCallback 固定为 callback
  • JSONP 开关参数为 jsonp。比如:http://localhost:8085/api/sample/form/get1?jsonp=1 输出 callback({"code":0,"msg":"OK"});http://localhost:8085/api/sample/form/get1 输出 {"code":0,"msg":"OK"}

操作步骤

  • 编写 MappingJackson2HttpMessageConverterSupportJsonp 类,且继承 MappingJackson2HttpMessageConverter 类。
  • 在 MappingJackson2HttpMessageConverterSupportJsonp 类中覆盖 writePrefix(在输出时,添加前缀) 和 writeSuffix(在输出时,添加后缀)。
  • 使用 MappingJackson2HttpMessageConverterSupportJsonp Bean 替换 MappingJackson2HttpMessageConverter Bean。

代码如下:

@Configuration
public class JsonpSupportConfig {

	@Bean
	public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(
			ObjectMapper objectMapper) {
		return new MappingJackson2HttpMessageConverterSupportJsonp(objectMapper);
	}
	
	private static class MappingJackson2HttpMessageConverterSupportJsonp extends MappingJackson2HttpMessageConverter {
		private final String PARAM_JSONP = "jsonp";
		public MappingJackson2HttpMessageConverterSupportJsonp(ObjectMapper objectMapper) {
			super(objectMapper);
		}
		
		@Override
		protected void writePrefix(JsonGenerator generator, Object object) throws IOException {
			if (this.isJsonp(object)) {
				generator.writeRaw("callback(");
			}
		}
		
		@Override
		protected void writeSuffix(JsonGenerator generator, Object object) throws IOException {
			if (this.isJsonp(object)) {
				generator.writeRaw(")");
			}
		}
		
		private boolean isJsonp(Object object) {
			RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
			ServletRequestAttributes servletAttributes = (ServletRequestAttributes) attributes;
			HttpServletRequest request = servletAttributes.getRequest();
			String jsonpStr = request.getParameter(PARAM_JSONP);
			
			if ("0".equals(jsonpStr)) { return false; }
			if ("1".equals(jsonpStr)) { return true; }
			return Boolean.valueOf(jsonpStr);
		}
		
	}
}

效果图:
在这里插入图片描述
在这里插入图片描述

spring boot 对 jsonp 的支持问题

spring 5.1 之前可以使用 AbstractJsonpResponseBodyAdvice 支持 JSONP,spring 5.1 之后将其移除了。

AbstractJsonpResponseBodyAdvice was deprecated starting from Spring 5.0.7 and 4.3.18 and in version 5.1 it is completely removed.

因为随着时间的推移,浏览器都支持了 CROS 。CROS 要比 JSONP 好。工作中,逐渐的转投 CROS。

参考

https://blog.csdn.net/sayyy/article/details/108399070
https://stackoverflow.com/questions/52845927/how-to-handle-jsonp-spring-framework-5-1

 

前言

  • springboot 2.1.1.RELEASE
  • 360 极速浏览器 12.0.1476.0 (正式版本) (32 位)
  • jquery 3.5.0
  • 接口跨域请求有两者方式:
    • jsonp
    • CORS

JSONP

JSONP (JSON with Padding) 是利用浏览器对 script 的资源引用没有同源限制,通过动态插入一个 script 标签,当资源加载到页面后会立即执行的原理实现跨域的。

JSONP 是一种非正式传输协议,具体做法是:用户传递一个 callback 参数给服务端。服务端返回数据时用 callback 参数包裹住 JSON 数据,形如 callback({name:'zhangsan',age:18})

JSONP 只支持 GET 请求 (不支持 POST 等其它类型的 HTTP 请求),它只支持跨域 HTTP 请求这种情况,不能解决不同域的两个页面之间如何进行 JavaScript 调用的问题。

JSONP 的优势在于支持老式浏览器,弊端也比较明显:需要客户端和服务端定制进行开发。

CORS

Cross-Origin Resource Sharing (CORS) 是 W3c 工作草案,它定义了在跨域访问资源时浏览器和服务器之间如何通信。CORS 背后的基本思想是使用自定义的 HTTP 头部允许浏览器和服务器相互了解对方,从而决定请求或响应成功与否。

CORS 的具体做法为:浏览器发现请求不符合同源策略时,给请求加一个请求头 Origin。服务端如果接受请求则在返回结果中加入一个响应头 Access-Control-Allow-Origin

CORS 与 JSONP 的使用目的相同,但是比 JSONP 更强大。CORS 支持所有的浏览器请求类型,承载的请求数据量更大(因为 URL 是有长度限制的,参考这里。以目前的技术看,URL 没有长度限制,那是不可想象的)。

CORS 也不是万能的,老旧的浏览器就不支持。

CORS 请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。下面的方法只在简单请求下做了测试。

springboot 启用 @CrossOrigin

springboot 很贴心的提供了不同粒度的控制。这里介绍全局设置。

  1. 添加注解 @CrossOrigin

    @CrossOrigin(origins = {"*"})
    @SpringBootApplication
    public class Application {
    ...
    }

    说明:origins 不建议使用 *(为了方便这里用 *。实际应用时,老老实实的一个一个的添加)。

  2. 或者 addCorsMappings

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
    	@Override
    	public void addCorsMappings(CorsRegistry registry) {
    		registry.addMapping("/api/**");
    	}
    	
    }
  3. 测试
    测试略。模拟跨域请求,可以在浏览器里发送 ajax 请求,参考这里(使用 jquery 调试 ajax 接口 - 2)

Http 请求如下(http://localhost:8085/api/sample/form/get1):

	GET /api/sample/form/get1 HTTP/1.1
	Host: localhost:8085
	Connection: keep-alive
	Accept: */*
	Origin: null
	User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36
	Sec-Fetch-Site: cross-site
	Sec-Fetch-Mode: cors
	Accept-Encoding: gzip, deflate, br
	Accept-Language: zh-CN,zh;q=0.9
Http 响应如下:
	HTTP/1.1 200
	Vary: Origin
	Vary: Access-Control-Request-Method
	Vary: Access-Control-Request-Headers
	Access-Control-Allow-Origin: *
	Content-Type: application/json;charset=UTF-8
	Transfer-Encoding: chunked
	Date: Fri, 04 Sep 2020 06:09:46 GMT

springboot 2.2.13.RELEASE 补充

  1. SpringBoot 注解 @CrossOrigin 不起作用

  2. addCorsMappings 方式依然有效。

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
    	@Override
    	public void addCorsMappings(CorsRegistry registry) {
    		registry.addMapping("/api/**");
    	}
    	
    }

    想了解更多,参考这里

参考

https://www.cnblogs.com/banning/p/6250677.html
https://zhuanlan.zhihu.com/p/38972475
https://www.cnblogs.com/zhaosq/p/10529803.html

【springboot】【若依 (ruoyi)】@RestController 接口跨域请求_若依跨域 - CSDN 博客

Web on Servlet Stack (spring.io)

CORS :: Spring Framework

 

posted @ 2024-06-27 10:36  CharyGao  阅读(121)  评论(0)    收藏  举报