[后端] java如何解决跨域问题

您所在的位置:网站首页 zuul跨域问题 [后端] java如何解决跨域问题

[后端] java如何解决跨域问题

2024-07-08 17:53| 来源: 网络整理| 查看: 265

最近遇到跨域问题,以下为多服务与单服务下的跨域问题解决方案~ 一.基于zuul网关解决跨域问题

1.跨域问题描述: 本人在基于Oauth2.0做鉴权/授权时,配合前端联调接口时,已经让前端请求时的请求头带上key:Authorization,但是前台报错为跨域问题,后台报错鉴权失败,于是跟踪错误,发现在网关处从header中一直拿不到这个 Authorization 这个属性的值(因为oauth 2的密码模式是需要请求头中带有token才能够完成鉴权),具体错误如下图所示: 跨域img-1

上图中可以明显看到请求中是存在 Authorization 这个属性的,但是从后台图片看是并没有拿到这个属性的: 跨域img-2

2.问题分析经过: 本人继续向下查找原因,发现通过 HttpRequest的api:getHeaderNames()可以找到请求头中的所有header属性,如下图: 跨域img-3

于是猜想是否有一层转换是将请求头中所有的key属性转化了小写,于是继续尝试 request.getHeader(“authorization”),但是结果还是出乎意料,返回结果也是空,于是开始从头理思路:

从前台开始报错为跨域问题,查看发生错误请求的类型为Preflighted,这让本人感到疑惑,于是查阅资料: 跨域img-4

查阅带预检(Preflighted)的跨域请求跨域原因有如下两种:

1). 除GET、HEAD和POST(only with application/x-www-form-urlencoded, multipart/form-data, text/plain Content-Type)以外的其他HTTP方法。 2). 请求中出现自定义HTTP头部。 以上摘自博客链接

此时豁然开朗,因为基于Oauth2的协议需要在请求中带上 Authorization 及其对应的token,所以自定义了请求头,且请求方不同源,所以浏览器(本次问题使用google浏览器)会发送两次请求:

1). 带预检(Preflighted)的跨域请求,此时请求类型为OPTIONS跨域img-5

2). 带真实数据的请求,此时才是我们真实想要的GET/POST请求跨域img-6

3.验证问题猜想: 如下图,断点处请求类型确实为 OPTIONS 跨域img-7

4.解决方案: 既然已经明确了问题所在,解决方案便随之而出了,由于本人是基于zuul网关做的鉴权/授权,所以解决方案也是基于zuul,仅提供参考: 1). 配置跨域过滤器,优先级最高,生效在路由前,判断如果是带预检的请求,则在响应头中放入允许跨域相关的属性,然后不再向下路由,具体代码如下:

import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Component public class CrossFilter extends ZuulFilter { /** * pre:可以在请求被路由之前调用 * route:在路由请求时候被调用 * post:在route和error过滤器之后被调用 * error:处理请求时发生错误时被调用 */ @Override public String filterType() { return FilterConstants.PRE_TYPE; } /** * 优先级为0,数字越大,优先级越低 */ @Override public int filterOrder() { return 0; } @Override public boolean shouldFilter() { RequestContext ctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); //只过滤OPTIONS 请求 if (request.getMethod().equals(RequestMethod.OPTIONS.name())) { return true; } if (!ctx.sendZuulResponse()) { return false; } return false; } @Override public Object run() { // logger.info("*****************FirstFilter run start*****************"); RequestContext ctx = RequestContext.getCurrentContext(); HttpServletResponse response = ctx.getResponse(); HttpServletRequest request = ctx.getRequest(); response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Headers", "Authorization, content-type, token, myauth, myAuth, userId, userid, RefreshToken"); response.setHeader("Access-Control-Allow-Methods", "POST,GET"); response.setHeader("Access-Control-Expose-Headers", "X-forwared-port, X-forwarded-host"); response.setHeader("Vary", "Origin,Access-Control-Request-Method,Access-Control-Request-Headers"); //不再路由 ctx.setSendZuulResponse(false); ctx.setResponseStatusCode(200); return null; } }

二. 另外附单体服务解决跨域方案 以下需要注意的点为 @Order(Integer.MIN_VALUE) ,这行代码的意思是将此过滤器的作用在所有过滤链最前端,至于原因本人会单独开一篇博客讨论。

import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.http.HttpMethod; import javax.servlet.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; @Configuration @Order(Integer.MIN_VALUE) public class CrossFilter implements Filter { @Override public void doFilter(ServletRequest request1, ServletResponse response1, FilterChain chain) throws IOException, ServletException { HttpServletRequest request = (HttpServletRequest) request1; HttpServletResponse response = (HttpServletResponse) response1; response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin")); response.setHeader("Access-Control-Allow-Credentials", "true"); response.setHeader("Access-Control-Allow-Headers", "Authorization, content-type, token, myauth, myAuth,userId , userid,RefreshToken"); response.setHeader("Access-Control-Allow-Methods", "POST,GET,OPTIONS"); response.setHeader("Access-Control-Expose-Headers", "X-forwared-port, X-forwarded-host,Content-Disposition"); response.setHeader("Vary", "Origin,Access-Control-Request-Method,Access-Control-Request-Headers"); if (!request.getMethod().equals(HttpMethod.OPTIONS.name())) { chain.doFilter(request, response); } } }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3