• 高德地图JSAPI 2.0使用Java代码代替Nginx进行反向代理产生CORS跨域


    解决前端访问高德产生的啥啥啥问题,反正问题交给后端做了,

    解决高德代理连接:

    高德地图JSAPI 2.0使用Java代码代替Nginx进行反向代理icon-default.png?t=N7T8https://blog.csdn.net/shechaojin/article/details/126267635?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166747082616782427444491%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=166747082616782427444491&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-126267635-null-null.142%5Ev62%5Epc_search_tree,201%5Ev3%5Econtrol,213%5Ev1%5Et3_control1&utm_term=java%E4%BD%BF%E7%94%A8%E9%AB%98%E5%BE%B7%E4%BB%A3%E7%90%86

    1. org.mitre.dsmiley.httpproxy
    2. smiley-http-proxy-servlet
    3. 1.12.1

     注册servlet组件 (ServletRegistrationBean) 

    1. @Bean
    2. public ServletRegistrationBean servletRegistrationAMapService() {
    3. ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ProxyServlet(), "/_AMapService/*");
    4. servletRegistrationBean.setName("AMapService");
    5. servletRegistrationBean.addInitParameter(ProxyServlet.P_TARGET_URI, "https://restapi.amap.com");
    6. servletRegistrationBean.addInitParameter(ProxyServlet.P_LOG, Boolean.FALSE.toString());
    7. return servletRegistrationBean;
    8. }
    9. @Bean
    10. public FilterRegistrationBean map() {
    11. FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
    12. filterRegistrationBean.setFilter(aMapServiceProxyFilter());
    13. filterRegistrationBean.addUrlPatterns("/_AMapService/*");
    14. filterRegistrationBean.setOrder(1);
    15. return filterRegistrationBean;
    16. }

    在Filter拦截器中对_AMapService的请求拼接jscode 

    1. private final String AMapJSCode = "xxxxxxxxxxxxx";
    2. @Override
    3. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    4. HttpServletRequest request = (HttpServletRequest) servletRequest;
    5. HttpServletResponse response = (HttpServletResponse) servletResponse;
    6. response.setHeader("Access-Control-Allow-Origin", "*");
    7. response.setHeader("Access-Control-Allow-Methods", "POST,GET,PUT,DELETE,OPTIONS");
    8. response.setHeader("Access-Control-Max-Age", "3600");
    9. StringBuilder allowHeaders = new StringBuilder();
    10. allowHeaders.append("accept,content-type,origin,referer,user-agent,Accept,Content-Type,Origin,Referer,User-Agent,Content-MD5,Authentication");
    11. response.setHeader("Access-Control-Allow-Headers", allowHeaders.toString());
    12. response.setHeader("Access-Control-Allow-Credentials", "true");
    13. response.setHeader("Access-Control-Expose-Headers", "version");
    14. response.setCharacterEncoding("UTF-8");
    15. response.setContentType("application/json;charset=utf-8");
    16. if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
    17. // 设置跨域配置
    18. response.setStatus(HttpServletResponse.SC_OK);
    19. } else {
    20. // 此处为核心代码 将jscode参数进行拼接
    21. String requestURI = request.getRequestURI();
    22. log.info("requestURI>>>{}", requestURI);
    23. boolean isAdd = requestURI.contains("_AMapService");
    24. HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(request) {
    25. @Override
    26. public String getQueryString() {
    27. if (isAdd) {
    28. return (super.getQueryString() + "&jscode=" + AMapJSCode);
    29. }
    30. return super.getQueryString();
    31. }
    32. };
    33. filterChain.doFilter(requestWrapper, response);
    34. }
    35. }

     产生跨域问题时,需要删除response

    1. HttpServletRequest request = (HttpServletRequest) servletRequest;
    2. HttpServletResponse response = (HttpServletResponse) servletResponse;
    3. // 此处为核心代码 将jscode参数进行拼接
    4. String requestURI = request.getRequestURI();
    5. log.info("requestURI>>>{}", requestURI);
    6. boolean isAdd = requestURI.contains("_AMapService");
    7. HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(request) {
    8. @Override
    9. public String getQueryString() {
    10. if (isAdd) {
    11. return (super.getQueryString() + "&jscode=" + securityKey);
    12. }
    13. return super.getQueryString();
    14. }
    15. };
    16. filterChain.doFilter(requestWrapper, response);

     解决跨域连接:JAVA Java 解决跨域问题_你好,未来的我的博客-CSDN博客_java解决跨域的三种方法JAVA | Java 解决跨域问题引言什么是跨域(CORS)什么情况会跨域解决方案前端解决方案后端解决方案具体方式一、使用Filter方式进行设置二、继承 HandlerInterceptorAdapter三、实现 WebMvcConfigurer四、使用Nginx配置五、使用 @CrossOrgin 注解Spring Cloud Gateway 跨域配置引言我们在开发过程中经常会遇到前后端分离而导致的跨域问题,导致无法获取返回结果。跨域就像分离前端和https://blog.csdn.net/lidongkui123/article/details/123720743?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166746964616782425123731%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=166746964616782425123731&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduend~default-1-123720743-null-null.142%5Ev62%5Epc_search_tree,201%5Ev3%5Econtrol,213%5Ev1%5Et3_control1&utm_term=java%E5%A4%84%E7%90%86%E8%B7%A8%E5%9F%9F&spm=1018.2226.3001.4187

    主要是这段:

    JAVA | Java 解决跨域问题


    引言

    我们在开发过程中经常会遇到前后端分离而导致的跨域问题,导致无法获取返回结果。跨域就像分离前端和后端的一道鸿沟,君在这边,她在那边,两两不能往来.

    什么是跨域(CORS)

    跨域(CORS)是指不同域名之间相互访问。跨域,指的是浏览器不能执行其他网站的脚本,它是由浏览器的同源策略所造成的,是浏览器对于JavaScript所定义的安全限制策略。

    什么情况会跨域

    • 同一协议, 如http或https
    • 同一IP地址, 如127.0.0.1
    • 同一端口, 如8080

    以上三个条件中有一个条件不同就会产生跨域问题。

    解决方案

    前端解决方案

    1. 使用JSONP方式实现跨域调用;
    2. 使用NodeJS服务器做为服务代理,前端发起请求到NodeJS服务器, NodeJS服务器代理转发请求到后端服务器;

    后端解决方案

    • nginx反向代理解决跨域
    • 服务端设置Response Header(响应头部)的Access-Control-Allow-Origin
    • 在需要跨域访问的类和方法中设置允许跨域访问(如Spring中使用@CrossOrigin注解);
    • 继承使用Spring Web的CorsFilter(适用于Spring MVC、Spring Boot)
    • 实现WebMvcConfigurer接口(适用于Spring Boot)

    具体方式

    一、使用Filter方式进行设置

    使用Filter过滤器来过滤服务请求,向请求端设置Response Header(响应头部)的Access-Control-Allow-Origin属性声明允许跨域访问。

    1. @WebFilter
    2. public class CorsFilter implements Filter {
    3. @Override
    4. public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
    5. HttpServletResponse response = (HttpServletResponse) res;
    6. response.setHeader("Access-Control-Allow-Origin", "*");
    7. response.setHeader("Access-Control-Allow-Methods", "*");
    8. response.setHeader("Access-Control-Max-Age", "3600");
    9. response.setHeader("Access-Control-Allow-Headers", "*");
    10. response.setHeader("Access-Control-Allow-Credentials", "true");
    11. chain.doFilter(req, res);
    12. }
    13. }

    二、继承 HandlerInterceptorAdapter

    1. @Component
    2. public class CrossInterceptor extends HandlerInterceptorAdapter {
    3. @Override
    4. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    5. response.setHeader("Access-Control-Allow-Origin", "*");
    6. response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
    7. response.setHeader("Access-Control-Max-Age", "3600");
    8. response.setHeader("Access-Control-Allow-Headers", "*");
    9. response.setHeader("Access-Control-Allow-Credentials", "true");
    10. return true;
    11. }
    12. }

    三、实现 WebMvcConfigurer

    1. @Configuration
    2. @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
    3. public class AppConfig implements WebMvcConfigurer {
    4. @Override
    5. public void addCorsMappings(CorsRegistry registry) {
    6. registry.addMapping("/**") // 拦截所有的请求
    7. .allowedOrigins("http://www.abc.com") // 可跨域的域名,可以为 *
    8. .allowCredentials(true)
    9. .allowedMethods("*") // 允许跨域的方法,可以单独配置
    10. .allowedHeaders("*"); // 允许跨域的请求头,可以单独配置
    11. }
    12. }
    13. 复制代码

    四、使用Nginx配置

    1. location / {
    2. add_header Access-Control-Allow-Origin *;
    3. add_header Access-Control-Allow-Headers X-Requested-With;
    4. add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;
    5. if ($request_method = 'OPTIONS') {
    6. return 204;
    7. }
    8. }
    9. 复制代码

    五、使用 @CrossOrgin 注解

    如果只是想部分接口跨域,且不想使用配置来管理的话,可以使用这种方式

    在Controller使用

    1. @CrossOrigin
    2. @RestController
    3. @RequestMapping("/user")
    4. public class UserController {
    5. @GetMapping("/{id}")
    6. public User get(@PathVariable Long id) {
    7. }
    8. @DeleteMapping("/{id}")
    9. public void remove(@PathVariable Long id) {
    10. }
    11. }

    在具体接口上使用

    1. @RestController
    2. @RequestMapping("/user")
    3. public class UserController {
    4. @CrossOrigin
    5. @GetMapping("/{id}")
    6. public User get(@PathVariable Long id) {
    7. }
    8. @DeleteMapping("/{id}")
    9. public void remove(@PathVariable Long id) {
    10. }
    11. }
    • 1

    Spring Cloud Gateway 跨域配置

    1. spring:
    2. cloud:
    3. gateway:
    4. globalcors:
    5. cors-configurations:
    6. '[/**]':
    7. # 允许跨域的源(网站域名/ip),设置*为全部
    8. # 允许跨域请求里的head字段,设置*为全部
    9. # 允许跨域的method, 默认为GETOPTIONS,设置*为全部
    10. allow-credentials: true
    11. allowed-origins:
    12. - "http://xb.abc.com"
    13. - "http://sf.xx.com"
    14. allowed-headers: "*"
    15. allowed-methods:
    16. - OPTIONS
    17. - GET
    18. - POST
    19. - DELETE
    20. - PUT
    21. - PATCH
    22. max-age: 3600

    注意: 通过gateway 转发的其他项目,不要进行配置跨域配置

    有时即使配置了也不会起作用,这时你可以根据浏览器控制的错误输出来查看问题,如果提示是 response 中 header 出现了重复的 Access-Control-* 请求头,可以进行如下操作

    1. import java.util.ArrayList;
    2. import org.springframework.cloud.gateway.filter.GatewayFilterChain;
    3. import org.springframework.cloud.gateway.filter.GlobalFilter;
    4. import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
    5. import org.springframework.core.Ordered;
    6. import org.springframework.http.HttpHeaders;
    7. import org.springframework.stereotype.Component;
    8. import org.springframework.web.server.ServerWebExchange;
    9. import reactor.core.publisher.Mono;
    10. @Component("corsResponseHeaderFilter")
    11. public class CorsResponseHeaderFilter implements GlobalFilter, Ordered {
    12. @Override
    13. public int getOrder() {
    14. // 指定此过滤器位于NettyWriteResponseFilter之后
    15. // 即待处理完响应体后接着处理响应头
    16. return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
    17. }
    18. @Override
    19. public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    20. return chain.filter(exchange).then(Mono.defer(() -> {
    21. exchange.getResponse().getHeaders().entrySet().stream()
    22. .filter(kv -> (kv.getValue() != null && kv.getValue().size() > 1))
    23. .filter(kv -> (
    24. kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)
    25. || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)
    26. || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS)
    27. || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS)
    28. || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_MAX_AGE)))
    29. .forEach(kv -> {
    30. kv.setValue(new ArrayList<String>() {{
    31. add(kv.getValue().get(0));
    32. }});
    33. });
    34. return chain.filter(exchange);
    35. }));
    36. }
    37. }

    作者:双鬼带单
    链接:https://juejin.cn/post/6874163312918003719
    来源:稀土掘金
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 相关阅读:
    String类的初始化?
    前端新手导航页--vue3--vue3-tour使用
    React 学习-6-列表 & keys
    【学习笔记】 字符串基础 : 后缀自动机(基础篇)
    【论文翻译】变更数据捕获和实时数据仓库框架
    【RT-Thread】nxp rt10xx 设备驱动框架之--Audio搭建和使用
    python正则表达式
    关于进程同步与互斥的一些概念(锁、cas、futex)
    太炫酷,3分钟学会,视频倒放技能
    【概念】make 与 configure
  • 原文地址:https://blog.csdn.net/qq_42553504/article/details/127675763