Web on Reactive Stack
目录
1、Spring WebFlux
1.1、Overview
1.2、Reactive Core
1.3、DispatcherHandler
1.4、Annotated Controllers
1.5、Functional Endpoints
1.6、URI Links
1.7、CORS
1.7.1、为什么会出现跨域问题
出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。
同源策略会阻止一个域的javascript脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)。
1.7.2、跨域后的限制
- 无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
- 无法接触非同源网页的 DOM
- 无法向非同源地址发送 AJAX 请求
1.7.3、Spring后端解决CORS跨域的方式
对于CORS的跨域请求,主要有以下几种方式可供选择:
- 返回新的CorsFilter
- 重写 WebMvcConfigurer
- 使用注解 @CrossOrigin
- 手动设置响应头 (HttpServletResponse)
- 自定web filter 实现跨域
注意事项:
- CorFilter / WebMvConfigurer / @CrossOrigin 需要 SpringMVC 4.2以上版本才支持,对应springBoot 1.3版本以上
- 上面前两种方式属于全局 CORS 配置,后两种属于局部 CORS配置。如果使用了局部跨域是会覆盖全局跨域的规则,所以可以通过 @CrossOrigin 注解来进行细粒度更高的跨域资源控制
- 其实无论哪种方案,最终目的都是修改响应头,向响应头中添加浏览器所要求的数据,进而实现跨域
1.7.3.1、返回新的 CorsFilter(全局跨域)
在任意配置类,返回一个 新的 CorsFIlter Bean ,并添加映射路径和具体的CORS配置路径。
import static org.springframework.http.HttpMethod.DELETE;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.http.HttpMethod.PUT;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
@Configuration
public class AppConfiger {
@Bean
CorsFilter corsFilter() {
final CorsConfiguration config = new CorsConfiguration();
// config.addAllowedOrigin("*");
config.addAllowedOriginPattern("*");
config.setAllowCredentials(Boolean.TRUE);
config.addAllowedMethod(GET);
config.addAllowedMethod(POST);
config.addAllowedMethod(PUT);
config.addAllowedMethod(DELETE);
config.addAllowedHeader("*");
config.addExposedHeader("*");
final UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
configSource.registerCorsConfiguration("/**", config);
return new CorsFilter(configSource);
}
}
1.7.3.2、重写 WebMvcConfigurer(全局跨域)
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 CorsConfiger implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowCredentials(true)
// .allowedOrigins("*")
.allowedOriginPatterns("*")
.allowedMethods(new String[] { "GET", "POST", "PUT", "DELETE" })
.allowedHeaders("*")
.exposedHeaders("*");
}
}
1.7.3.3、使用注解 (局部跨域)
在控制器类上、方法上使用注解 @CrossOrigin
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.util.DigestUtils.md5DigestAsHex;
import static org.springframework.web.bind.annotation.RequestMethod.DELETE;
import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import static org.springframework.web.bind.annotation.RequestMethod.PUT;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin(
originPatterns = "*",
allowCredentials = "true",
allowedHeaders = "*",
exposedHeaders = "*",
methods = { GET, POST, PUT, DELETE }
)
public class IndexController {
@GetMapping(path = "/", produces = APPLICATION_JSON_VALUE)
public Map<String, Object> execute() {
return new HashMap<String, Object>(2) {
private static final long serialVersionUID = -530647985007348495L;
{
put("timestamp", System.currentTimeMillis());
put("num", md5DigestAsHex(UUID.randomUUID().toString().getBytes(UTF_8)));
}
};
}
}
1.7.3.4、手动设置响应头(局部跨域)
使用 HttpServletResponse 对象添加响应头(Access-Control-Allow-Origin)来授权原始域,
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE;
import static org.springframework.util.DigestUtils.md5DigestAsHex;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
@GetMapping(path = "/", produces = APPLICATION_JSON_VALUE)
public Map<String, Object> execute(HttpServletResponse response) {
response.addHeader("Access-Control-Allow-Credentials", "true");
response.addHeader("Access-Control-Allow-Headers", "*");
response.addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Expose-Headers", "*");
return new HashMap<String, Object>(2) {
private static final long serialVersionUID = -530647985007348495L;
{
put("timestamp", System.currentTimeMillis());
put("num", md5DigestAsHex(UUID.randomUUID().toString().getBytes(UTF_8)));
}
};
}
}
1.7.3.5、使用自定义filter实现跨域
1.7.3.5.1、@Bean注解方式
1.7.3.5.1.1、自定义过滤器
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
final HttpServletResponse resp = (HttpServletResponse) response;
resp.addHeader("Access-Control-Allow-Credentials", "true");
resp.addHeader("Access-Control-Allow-Headers", "*");
resp.addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
resp.addHeader("Access-Control-Allow-Origin", "*");
resp.addHeader("Access-Control-Expose-Headers", "*");
chain.doFilter(request, resp);
}
}
1.7.3.5.1.2、Bean注入
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import com.cnblogs.javalouvre.filter.CorsFilter;
@Configuration
public class FilterConfiger {
@Bean
@Order(1)
public FilterRegistrationBean<CorsFilter> corsFilter() {
final FilterRegistrationBean<CorsFilter> filterRegistrationBean = new FilterRegistrationBean<>();
filterRegistrationBean.setFilter(new CorsFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setName("corsFilter");
return filterRegistrationBean;
}
}
1.7.3.5.2、WebFilter注解方式
1.7.3.5.2.1、自定义过滤器
使用@WebFilter标注当前过滤器
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
@WebFilter(displayName = "corsFilter", urlPatterns = "/*")
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
final HttpServletResponse resp = (HttpServletResponse) response;
resp.addHeader("Access-Control-Allow-Credentials", "true");
resp.addHeader("Access-Control-Allow-Headers", "*");
resp.addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
resp.addHeader("Access-Control-Allow-Origin", "*");
resp.addHeader("Access-Control-Expose-Headers", "*");
chain.doFilter(request, resp);
}
}
1.7.3.5.2.2、注入
使用@ServletComponentScan注解,注入容器
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import com.cnblogs.javalouvre.filter.CorsFilter;
@ServletComponentScan(basePackageClasses = { CorsFilter.class })
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
1.8、Web Security
1.9、View Technologies
1.10、HTTP Caching
1.11、WebFlux Config
1.12、HTTP/2
2、WebClient
3、WebSockets
4、Testing
5、RSocket
6、Reactive Libraries
-----------------------------------------------------------------------------------------------------------
薔薇猛虎皆成個性,陽光雨露俱是天恩!
薔薇猛虎皆成個性,陽光雨露俱是天恩!