真正解决 JFinal CORS 跨域及 OPTIONS 预检等问题

先看效果

B756BBE40C17E8BACDD089AA5161C7F9-small(1).jpg

CDFD6F6D581DA9A1251FBA46C428CF83-small(1).jpg


折腾很久,之前搜了一大堆结果但没有一个真正能用的:

http://www.jfinal.com/share/260

http://www.jfinal.com/share/1748

http://www.jfinal.com/share/1137

http://www.jfinal.com/share/1024

...


它们都有一个致命的问题:

"Access-Control-Allow-Origin", "*"

这样设置是过不了浏览器 OPTIONS 预检的,浏览器会拦截然后报错:

87E0BAB79CF3400A1E6B300BA000D4F9-small(2).jpg




需要把 "*" 替换成实际的 origin:

public class DemoAppConfig extends JFinalConfig {

  public void configInterceptor(Interceptors me) {
    me.add(new Interceptor() {
  
      @Override
      public void intercept(Invocation inv) {
  
        Controller controller = inv.getController();
        HttpServletRequest request = controller == null ? null : controller.getRequest();
        if (request == null) {
          return;
        }
  
        String origin = request.getHeader("origin");
        String corsHeaders = request.getHeader("access-control-request-headers");
        String corsMethod = request.getHeader("access-control-request-method");
  
        HttpServletResponse response = controller.getResponse();
        response.setHeader("Access-Control-Allow-Origin", StringUtil.isEmpty(origin, true) ? "*" : origin);
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Headers", StringUtil.isEmpty(corsHeaders, true) ? "*" : corsHeaders);
        response.setHeader("Access-Control-Allow-Methods", StringUtil.isEmpty(corsMethod, true) ? "*" : corsMethod);
        response.setHeader("Access-Control-Max-Age", "86400");
  
        if ("OPTIONS".equals(request.getMethod().toUpperCase())) {
          controller.renderJson("{}");
          return;
        }
  
        inv.invoke();
      }
  
    });

  }

}


完整项目见腾讯 APIJSON 的 Demo 项目 APIJSONFinal

https://github.com/APIJSON/APIJSON-Demo/tree/master/APIJSON-Java-Server/APIJSONFinal

评论区

sioui

2020-11-24 10:02

跨域我都在nginx处理,即便有修改也不用重启项目,只要nginx reload即可

TommyLemon

2020-11-24 10:26

@sioui 这也是一个可行的方案,用 Node 服务做代理也可以,但和 Nginx 一样都需要对每个要跨域的 host 进行配置,配置麻烦又很不灵活。我以上这个方案是任何前端网页,任何 host 都可以

海哥

2020-11-24 10:27

jfinal 已经内置解决方案了, https://gitee.com/jfinal/jfinal/tree/master/src/main/java/com/jfinal/ext/cors

TommyLemon

2020-11-24 10:31

@海哥 我之前看过了,host 必须写死在注解里,这个适用范围有限,而且碰到像我在本地打开一个非本地的网页(例如自己电脑打开 apijson.org/auto),这种就会导致 OPTIONS 和 POST JSON 其中一个不能通过,从而整个请求失败

TommyLemon

2020-11-24 10:33

还有另一个可行的方案就是把网页工程嵌入后端服务工程,共用同一个 host,这样就不存在跨域问题了,不需要做其它任何配置、任何代理都行。只是这种做法又从前后端分离回到了以前类似 JSP 的做法了,不符合我的需求。

steven_lhcb_9527

2020-12-10 08:45

觉得在nginx里面进行处理应该比较好吧