高德地图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

<dependency>
  <groupId>org.mitre.dsmiley.httpproxy</groupId>
  <artifactId>smiley-http-proxy-servlet</artifactId>
  <version>1.12.1</version>
</dependency>

 注册servlet组件 (ServletRegistrationBean) 

    @Bean
    public ServletRegistrationBean servletRegistrationAMapService() {
        ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new ProxyServlet(), "/_AMapService/*");
        servletRegistrationBean.setName("AMapService");
        servletRegistrationBean.addInitParameter(ProxyServlet.P_TARGET_URI, "https://restapi.amap.com");
        servletRegistrationBean.addInitParameter(ProxyServlet.P_LOG, Boolean.FALSE.toString());
        return servletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean<AMapServiceProxyFilter> map() {
        FilterRegistrationBean<AMapServiceProxyFilter> filterRegistrationBean = new FilterRegistrationBean();
        filterRegistrationBean.setFilter(aMapServiceProxyFilter());
        filterRegistrationBean.addUrlPatterns("/_AMapService/*");
        filterRegistrationBean.setOrder(1);
        return filterRegistrationBean;
    }

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


    private final String AMapJSCode = "xxxxxxxxxxxxx";

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST,GET,PUT,DELETE,OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        StringBuilder allowHeaders = new StringBuilder();
        allowHeaders.append("accept,content-type,origin,referer,user-agent,Accept,Content-Type,Origin,Referer,User-Agent,Content-MD5,Authentication");
        response.setHeader("Access-Control-Allow-Headers", allowHeaders.toString());
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Expose-Headers", "version");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json;charset=utf-8");
        if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
            // 设置跨域配置
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            // 此处为核心代码 将jscode参数进行拼接
            String requestURI = request.getRequestURI();
            log.info("requestURI>>>{}", requestURI);
            boolean isAdd = requestURI.contains("_AMapService");
            HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(request) {
                @Override
                public String getQueryString() {
                    if (isAdd) {
                        return (super.getQueryString() + "&jscode=" + AMapJSCode);
                    }
                    return super.getQueryString();
                }
            };
            filterChain.doFilter(requestWrapper, response);
        }
    }

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

 HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        // 此处为核心代码 将jscode参数进行拼接
        String requestURI = request.getRequestURI();
        log.info("requestURI>>>{}", requestURI);
        boolean isAdd = requestURI.contains("_AMapService");
        HttpServletRequestWrapper requestWrapper = new HttpServletRequestWrapper(request) {
            @Override
            public String getQueryString() {
                if (isAdd) {
                    return (super.getQueryString() + "&jscode=" + securityKey);
                }
                return super.getQueryString();
            }
        };
        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属性声明允许跨域访问。

@WebFilter
public class CorsFilter implements Filter {  

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {  
        HttpServletResponse response = (HttpServletResponse) res;  
        response.setHeader("Access-Control-Allow-Origin", "*");  
        response.setHeader("Access-Control-Allow-Methods", "*");  
        response.setHeader("Access-Control-Max-Age", "3600");  
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        chain.doFilter(req, res);  
    }  
}

二、继承 HandlerInterceptorAdapter

@Component
public class CrossInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        return true;
    }
}

三、实现 WebMvcConfigurer

@Configuration
@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
public class AppConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")  // 拦截所有的请求
                .allowedOrigins("http://www.abc.com")  // 可跨域的域名,可以为 *
                .allowCredentials(true)
                .allowedMethods("*")   // 允许跨域的方法,可以单独配置
                .allowedHeaders("*");  // 允许跨域的请求头,可以单独配置
    }
}

复制代码

四、使用Nginx配置

location / {
   add_header Access-Control-Allow-Origin *;
   add_header Access-Control-Allow-Headers X-Requested-With;
   add_header Access-Control-Allow-Methods GET,POST,PUT,DELETE,OPTIONS;

   if ($request_method = 'OPTIONS') {
     return 204;
   }
}
复制代码

五、使用 @CrossOrgin 注解

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

在Controller使用

@CrossOrigin
@RestController
@RequestMapping("/user")
public class UserController {

	@GetMapping("/{id}")
	public User get(@PathVariable Long id) {
		
	}

	@DeleteMapping("/{id}")
	public void remove(@PathVariable Long id) {

	}
}

在具体接口上使用

@RestController
@RequestMapping("/user")
public class UserController {

	@CrossOrigin
	@GetMapping("/{id}")
	public User get(@PathVariable Long id) {
		
	}

	@DeleteMapping("/{id}")
	public void remove(@PathVariable Long id) {

	}
}
  • 1

Spring Cloud Gateway 跨域配置

spring: 
  cloud:
    gateway:
      globalcors:
        cors-configurations:
          '[/**]':
            # 允许跨域的源(网站域名/ip),设置*为全部
            # 允许跨域请求里的head字段,设置*为全部
            # 允许跨域的method, 默认为GET和OPTIONS,设置*为全部
            allow-credentials: true
            allowed-origins:
              - "http://xb.abc.com"
              - "http://sf.xx.com"
            allowed-headers: "*"
            allowed-methods:
              - OPTIONS
              - GET
              - POST
              - DELETE
              - PUT
              - PATCH
            max-age: 3600

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

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

import java.util.ArrayList;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component("corsResponseHeaderFilter")
public class CorsResponseHeaderFilter implements GlobalFilter, Ordered {

  @Override
  public int getOrder() {
    // 指定此过滤器位于NettyWriteResponseFilter之后
    // 即待处理完响应体后接着处理响应头
    return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
  }

  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    return chain.filter(exchange).then(Mono.defer(() -> {
      exchange.getResponse().getHeaders().entrySet().stream()
          .filter(kv -> (kv.getValue() != null && kv.getValue().size() > 1))
          .filter(kv -> (
              kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)
                  || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)
                  || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS)
                  || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS)
                  || kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_MAX_AGE)))
          .forEach(kv -> {
            kv.setValue(new ArrayList<String>() {{
              add(kv.getValue().get(0));
            }});
          });
      return chain.filter(exchange);
    }));
  }
}

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

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Silence丶你的名字

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值