2020-06 补充: 在Controller中添加了跨域配置的代码,跨域访问的ajax任然失败:反查Controller代码之前filter或者其它早于JFinalFilter执行的过滤器中是否对跨域访问时,浏览器发送http的option(预请求)是否正常处理。
具体处理根据自己实际情况修正代码,如果缺乏相关知识,请查询“预检请求(Preflight Request)”。
1 分析:
设置:getResponse().addHeader("Access-Control-Allow-Origin", "*");在不同版本的浏览器中可能报错:
IE报错信息:http://localhost/auth/covert?code=c30643cd-fdfc-4d97-bcc9-eb74046c6d47 的 XMLHttpRequest 需要跨域资源共享(CORS)。
Chrome: jquery-1.11.0.js:9666 Access to XMLHttpRequest at 'http://localhost/auth/covert?code=ca36d3f6-1338-4242-8f7a-fd96e2ada46c' from origin 'http://127.0.0.1:8020' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Failed to load xxxxxxxxxxxxxx : The value of the ‘Access-Control-Allow-Origin’ header in the response must not be the wildcard ‘*’ when the request’s credentials mode is ‘include’. Origin ‘http://127.0.0.1’ is therefore not allowed access. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
jquery-1.11.0.js:9666 Access to XMLHttpRequest at 'http://localhost/auth/covert?code=4921aab6-7cf1-47f8-8c05-c618e56988b4' from origin 'http://127.0.0.1:8020' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
2 代码实现
模拟各位网友反馈问题后调整后的代码如下:
基于jquery的ajax访问:
ajax:function(url,data,callback){ var param={ type:"post", async:false, // true 异步,false 同步 url:url, data:data, dataType:"json", header:{ token:"abc" }, error:function(xhr,status,error){ console.log("ajax错误:xhr",xhr); console.log("ajax错误:status",status); console.log("ajax错误:error",error); }, success:function(result,status,xhr){ callback(result); }, // 下面的两行代码,就是解决跨域的关键 xhrFields: {withCredentials: true}, crossDomain: true }; $.ajax(param); }
java代码:Controller的方法上
/** * * 使用上面生成的code置换token:code只能使用一次 * */ public void covert(String code) { // String origin=getRequest().getHeader("Origin"); // getResponse().addHeader("Access-Control-Allow-Origin", origin); // getResponse().addHeader("Access-Control-Allow-Credentials", "true"); // getResponse().addHeader("Access-Control-Allow-Methods","POST,GET,OPTIONS,DELETE"); //支持的http 动作 // getResponse().addHeader("Access-Control-Allow-Headers","simple headers,Accept,Accept-Language,Content-Language,Content-Type,token"); //响应头 请按照自己需求添加。 String origin=getRequest().getHeader("Origin"); getResponse().addHeader("Access-Control-Allow-Origin", origin); getResponse().addHeader("Access-Control-Allow-Credentials", "true"); getResponse().addHeader("Access-Control-Allow-Methods","*"); //使用通配符 getResponse().addHeader("Access-Control-Allow-Headers","*"); //使用通配符 String token= TokenCache.get(code); String refresh_token= TokenCache.get(code+"_refresh"); if(token==null) { renderJson(Response.fail("code过期,置换token失败!")); }else { renderJson(Response.ok("token", token).set("refresh_token", refresh_token)); } }
通过请求,明确跨域的来源。
3 答疑
3.1 header添加token或者Authorization,做前后分离授权
ajax中添加headers,如果不是http协议支持的header,跨域时浏览器安全策略直接阻止发送(观察后台:是否收到http request)。
IE:SCRIPT7002: XMLHttpRequest: 网络错误 0x80070005, 拒绝访问。
Chrome:jquery-1.11.0.js:9666 Access to XMLHttpRequest at 'http://localhost/auth/covert' from origin 'http://127.0.0.1:8020' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: Redirect is not allowed for a preflight request.
分析:通过浏览器观察先发option请求,为什么呢?其实就是“"预请求"”,即设置Access-Control-Allow-Headers。
参考:ajax跨域 自定义header问题总结 https://www.cnblogs.com/holdon521/p/6225045.html
3.2 cors-filter第三方库没有使用过
分析一下:如果Tomcat能够部署成功,理论上undertow应该也可以。
配置:cors.properties
cors.allowGenericHttpRequests=true cors.allowOrigin=* cors.allowSubdomains=false cors.supportedMethods=GET, PUT, HEAD, POST, DELETE, OPTIONS cors.supportedHeaders=Origin, X-Requested-With, Content-Type, Accept, Authorization cors.exposedHeaders= cors.supportsCredentials=true cors.maxAge=3600
UndertowServer启动:
UndertowServer server = UndertowServer.create(AppConfig.class); //配置shiro server.configWeb(webBuilder -> { webBuilder.addListener(EnvironmentLoaderListener.class.getName()); webBuilder.addFilter("ShiroFilter", ShiroFilter.class.getName()); webBuilder.addFilterInitParam("ShiroFilter", "configPath", "classpath:shiro.ini"); webBuilder.addFilterUrlMapping("ShiroFilter", "/*", DispatcherType.REQUEST); webBuilder.addFilterUrlMapping("ShiroFilter", "/*", DispatcherType.FORWARD); webBuilder.addFilterUrlMapping("ShiroFilter", "/*", DispatcherType.INCLUDE); webBuilder.addFilterUrlMapping("ShiroFilter", "/*", DispatcherType.ERROR); // webBuilder.addFilterInitParam("ShiroFilter", "key", "value"); webBuilder.addFilter("CorsFilter", CORSFilter.class.getName()); webBuilder.addFilterInitParam("CorsFilter", "cors.configurationFile", "cors.properties"); webBuilder.addFilterUrlMapping("CorsFilter", "/*", DispatcherType.REQUEST); webBuilder.addFilterUrlMapping("CorsFilter", "/*", DispatcherType.FORWARD); webBuilder.addFilterUrlMapping("CorsFilter", "/*", DispatcherType.INCLUDE); webBuilder.addFilterUrlMapping("CorsFilter", "/*", DispatcherType.ERROR); }); server.start();