1、起因
最近开发的项目前台使用axios发送HTTP请求,在打开控制台的时候出现缺少相关响应头的警告。
后台使用jfinal,#spring 有CrossOrign 注解可以处理cross请求,也可以配置类实现。
2、过程
1.注解
`@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CrossOrign {
/**
* @info 例外路径,即不添加corss的响应头信息的方法
* @return
*/
String[] exceptionPath() default {};
}
- 这里使用反射获取注解的相关信息;
public class AnnotationUtil {
// 指定包下的所有类名
private static List<String> list = new ArrayList<>();
// 可以访问的地址
private static List<String> allowPath = new ArrayList<>();
static {
List<String> list = PackageUtil.getClassName("com.sinosoft.controller");
if (list != null) {
AnnotationUtil.list = list;
getAccessPath();
}
}
/**
* @info 获取可以访问的路径
*/
private static void getAccessPath() {
final String slash = "/";
for (String str : AnnotationUtil.list) {
try {
Class<?> clazz = Class.forName(str);
ControllerBind bind = clazz.getAnnotation(ControllerBind.class);
if (bind != null) {
String ck = bind.controllerKey();
CrossOrign co = clazz.getAnnotation(CrossOrign.class);
if (co != null) {
String[] method = co.exceptionPath();
Method[] methods = clazz.getDeclaredMethods();
// 所有方法名
List<String> list = new ArrayList<>();
for (Method method2 : methods) {
list.add(slash + method2.getName());
}
list.removeAll(Arrays.asList(method));
// 允许访问的路径
allowPath.add(ck);
for (String string : list) {
allowPath.add(ck + string);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* @info 校验地址
* @param uri
* @return
*/
public static boolean validation(String uri) {
return allowPath.contains(uri);
}
3.后台配置一个过滤器,只过滤添加了@CrossOrign和不在 exceptionPath的方法(jfinal 自定义的controller 继承了Controller抽象类,除了index方法,剩下的方法方法名即为action)
public class CorsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
String uri = request.getRequestURI();
String options = "OPTIONS";
String method = request.getMethod();
String contextPath = request.getContextPath();
// 如果URL地址最后有/ 需要替换成""
uri = uri.replace(contextPath, "");
uri = uri.endsWith("/") ? uri.substring(0, uri.length() - 1) : uri;
boolean flag = AnnotationUtil.validation(uri);
if (flag) {
System.out.println(uri + "可以添加跨域响应头");
// 指定允许其他域名访问
response.addHeader("Access-Control-allow-Origin", "*");
// 响应类型
response.addHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With,Content-Type, Accept");
// 响应头设置
response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT,DELETE");
// axios的post请求第一次会进行预请求,get方法试用qs.stringify()方法可以不进行预请求
if (options.equals(method) || options.toLowerCase().equals(method)) {
return;
}
}
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
// 注意:这里的filter需要配置在com.jfinal.core.JFinalFilter jfinal过滤器的前面
4.将我们的自定义注解添加到需要的controller中,启动,完成
5.nginx也可以解决cross跨域的问题