最近因为这个问题耗费了几天时间,觉得可能大家以后工作中有可能碰到,所以记录下来

前端是VUE框架的axios请求模式,后端采用springboot做的一个授权和认证服务

postman一切正常,然后开始联调发生悲剧!

前端说后端有问题,跨域没解决,开始动手,先解决认证服务器跨域问题

一般先在WebSecurityConfigurerAdapter实现里添加允许跨域

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            ...
            .and().cors()
            .and().csrf().disable()
    ;
}

发现不起作用,参考源码问题提问中搜索cors的问题,发现有专门的文档说明,于是添加

@Bean
CorsConfigurationSource corsConfigurationSource(){
      CorsConfiguration corsConfiguration=new CorsConfiguration();
      corsConfiguration.setAllowedOrigins(Arrays.asList("http://localhost:8016/oauth/token"));
      corsConfiguration.setAllowedMethods(Arrays.asList("POST, GET, OPTIONS, DELETE, PUT, HEAD"));
    UrlBasedCorsConfigurationSource source =new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", corsConfiguration);
    return source;
}

发现还是不起作用,然后前端就说跨域请求头报错(他只知道跨域问题,很简单的,至少他这么认为),索性尝试换另外一种思路,有没有cors关于请求头的拦截器呢(因为接口没有涉及log,所以想加个拦截器看看,至少保证前端传递的参数是正确的),找到了

@Configuration
public class CorsConfig {
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("*");
        config.setAllowCredentials(true);
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        config.addExposedHeader("Authorization");
        config.addExposedHeader("Content-Disposition");
        config.addExposedHeader("Content-Type");
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);
        return new CorsFilter(configSource);
    }
}

发现功能和上面一个配置有点像,继续找新的 WebMvcConfigurationSupport也有同样配置

@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("X-Access-Token");
        log.debug("允许跨域配置成功!");

    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new CrossInterceptor()).addPathPatterns("/**");
        log.debug("跨域拦截器注册成功!");

    }


}

还是不行,头有点懵(心里有点没底),然后决定第二天重新来试

新的一天新思路,找到前端然后硬着头皮让他起服务(估计他心里觉得我存粹在瞎折腾),无意识的点了下他的请求,

OPTIONS,发现都在401错误,然后闲聊发现它的请求方式和我们常见的ajax和js还是有点不同

 return axios({
    url: 'http://192.168.1.136:8016/oauth/token',
    method: 'post',
    data: data,
    ]
  })

axios,然后就专门搜了这个请求模式。发现在修改请求头模式下,都会发送一个预请求OPTIONS,然后还真被我发现,原来只有预请求正确的情况下才会有正式的请求,于是添加拦截器,如果预请求成功,就更改响应状态

@Log4j2
@Configuration
@ConfigurationProperties(prefix = "cross")
public class CrossInterceptor implements HandlerInterceptor {
    private static List<String> allowHosts;

    //配置允许跨域的域名
    public void setAllow(String allow) {
        if (allow != null) {
            allowHosts = Arrays.asList(allow.split(","));
        }
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String origin = request.getHeader(HttpHeaders.ORIGIN);
        if (origin != null) {
            if (allowHosts.contains(origin)) {
                response.setHeader("Access-Control-Allow-Origin", "*");
                response.setHeader("Access-Control-Allow-Credentials", "true");
                response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT, HEAD");
                if(request.getMethod().equals("OPTIONS")){
                    response.setHeader("Access-Control-Allow-Headers", "Content-Type");
                    response.setStatus(HttpServletResponse.SC_OK);
                }else{
                    response.setHeader("Access-Control-Allow-Headers", "*");
                }
            } else {
                log.warn("跨域失败:" + origin);
            }
        }
        return true;
    }
}

配置文件

cross:
  allow: http://192.168.1.155:8080,http://localhost:136,http://localhost:8080

还是401,也亏的是心态好(问题始终要解决),仔细观察发现,预请求居然过了,被拦截的是post,然后继续。。。。

耐心发现还是有收获的,401状态有返回响应UnAuthorization ,虽然内心有一万种觉得是前端请求有问题(他今天被我折腾的心态崩了),但还是忍住了,过一天再问

第三天了,继续看关于oauth2源码内容,既然要证明前端有问题,必须给出证据(以理服人),不是接口问题吗,找到源码接口/oauth/token,DEBUG模式开启!

 

心平气和又找他谈话去,然后他改正,发现还是有问题,直接找了份百度正规的截图给他

axios({
  url: '/user',
  method: 'post',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  },
  transformRequest: [function (data) {
    // Do whatever you want to transform the data
    let ret = ''
    for (let it in data) {
      ret += encodeURIComponent(it) + '=' + encodeURIComponent(data[it]) + '&'
    }
    return ret
  }],
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded'
  }
})
然后进行对比,Content-Type,发现表单提交类型不对,难怪没参数(这里也不是一步发现的),然后改正,终于不报错了,总算送了口气!

下午接着调试资源服务,加上cors拦截器配置,还是出了问题!

{
    "code": "1003",
    "data": "",
    "message": "用户未登录或长时间未操作,请重新登录"
}

虽然自己准确知道了问题的来源(这个异常就是我封装的),但是前端已经完全处于不信任和情绪状态,只能截图给他了,不敢说他错误,就说让他把传参改成固定参数,我测试下其他(自己先测试发现正常),结果改正后他自己发现正确了,然后他又说了一大堆。。。

  这次问题自己总结出几个道理

1遇到问题真的需要的不是技术,是耐心和细心,希望自己能保持它

2证据比什么都总要,在让别人承认错误的时候,永远不要陷入怀疑中

3与人沟通不要跟着别人节奏走,心态要保持不受影响

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Logo

前往低代码交流专区

更多推荐