解决前端访问高德产生的啥啥啥问题,反正问题交给后端做了,
解决高德代理连接:
-
org.mitre.dsmiley.httpproxy -
smiley-http-proxy-servlet -
1.12.1
注册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
map() { - FilterRegistrationBean
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);
- }
- }
- 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);
主要是这段:

我们在开发过程中经常会遇到前后端分离而导致的跨域问题,导致无法获取返回结果。跨域就像分离前端和后端的一道鸿沟,君在这边,她在那边,两两不能往来.
跨域(CORS)是指不同域名之间相互访问。跨域,指的是浏览器不能执行其他网站的脚本,它是由浏览器的同源策略所造成的,是浏览器对于JavaScript所定义的安全限制策略。
以上三个条件中有一个条件不同就会产生跨域问题。
使用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);
- }
- }
- @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;
- }
- }
-
- @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("*"); // 允许跨域的请求头,可以单独配置
- }
- }
-
- 复制代码
- 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) {
-
- }
- }
- 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
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。