发表于: 2019-01-10 20:10:29

2 1035


20190110

1.学到的知识

1.1.记录问题:

1.1.1.报错信息

{

    "timestamp": "2019-01-10T01:12:37.257+0000",

    "status": 500,

    "error": "Internal Server Error",

    "message": "GENERAL"

}

首先查看到是控制台打印的日志

2019-01-10 09:54:32.061  WARN 10022 --- [freshExecutor-0] c.n.d.s.t.d.RetryableEurekaHttpClient    : Request execution failed with message: java.net.UnknownHostException: standalone: Name or service not known
2019-01-10 09:54:32.061 ERROR 10022 --- [freshExecutor-0] com.netflix.discovery.DiscoveryClient    : DiscoveryClient_EUREKA-SERVICE/eureka-service:ad26a51ef5603485107a85d7d378d59b - was unable to refresh its cache! status = Cannot execute request on any known server

at com.netflix.discovery.DiscoveryClient.fetchRegistry(DiscoveryClient.java:965) [eureka-client-1.9.2.jar!/:1.9.2]
at com.netflix.discovery.DiscoveryClient.refreshRegistry(DiscoveryClient.java:1471) [eureka-client-1.9.2.jar!/:1.9.2]
at com.netflix.discovery.DiscoveryClient$CacheRefreshThread.run(DiscoveryClient.java:1438) [eureka-client-1.9.2.jar!/:1.9.2]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_171]
at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_171]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_171]

然后自己找到了注册中心eureka日志

  com.sun.jersey.api.client.ClientHandlerException: java.net.UnknownHostException: standalone: Name or service not known
  	at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:187) ~[jersey-apache-client4-1.19.1.jar!/:1.19.1] com.netflix.discovery.shared.transport.decorator.EurekaHttpClientDecorator.getApplications(EurekaHttpClientDecorator.java:134) [eureka-client-1.9.2.jar!/:1.9.2]
  	at com.netflix.discovery.DiscoveryClient.getAndStoreFullRegistry(DiscoveryClient.java:1051) [eureka-client-1.9.2.jar!/:1.9.2]
  Caused by: java.net.UnknownHostException: standalone: Name or service not known
  	at java.net.Inet4AddressImpl.lookupAllHostAddr(Native Method) ~[na:1.8.0_171]
  	at java.net.InetAddress$2.lookupAllHostAddr(InetAddress.java:928) ~[na:1.8.0_171]
  	at java.net.InetAddress.getAddressesFromNameService(InetAddress.java:1323) ~[na:1.8.0_171]
  	at java.net.InetAddress.getAllByName0(InetAddress.java:1276) ~[na:1.8.0_171]
  	at java.net.InetAddress.getAllByName(InetAddress.java:1192) ~[na:1.8.0_171]
  	at java.net.InetAddress.getAllByName(InetAddress.java:1126) ~[na:1.8.0_171]
  	at org.apache.http.impl.conn.SystemDefaultDnsResolver.resolve(SystemDefaultDnsResolver.java:45) ~[httpclient-4.5.6.jar!/:4.5.6]
  	at org.apache.http.impl.conn.DefaultClientConnectionOperator.resolveHostname(DefaultClientConnectionOperator.java:263) ~[httpclient-4.5.6.jar!/:4.5.6]
  	at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:162) ~[httpclient-4.5.6.jar!/:4.5.6]
  	at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:144) ~[httpclient-4.5.6.jar!/:4.5.6]
  	at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:134) ~[httpclient-4.5.6.jar!/:4.5.6]
  	at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:610) ~[httpclient-4.5.6.jar!/:4.5.6]
  	at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:445) ~[httpclient-4.5.6.jar!/:4.5.6]
  	at org.apache.http.impl.client.AbstractHttpClient.doExecute(AbstractHttpClient.java:835) ~[httpclient-4.5.6.jar!/:4.5.6]
  	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:118) ~[httpclient-4.5.6.jar!/:4.5.6]
  	at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:56) ~[httpclient-4.5.6.jar!/:4.5.6]
  	at com.sun.jersey.client.apache4.ApacheHttpClient4Handler.handle(ApacheHttpClient4Handler.java:173) ~[jersey-apache-client4-1.19.1.jar!/:1.19.1]
  	... 30 common frames omitted

zuul中控制台日志:

property: sources-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647
2019-01-10 09:58:07.209  INFO 20856 --- [nio-7888-exec-2] c.n.l.DynamicServerListLoadBalancer      : DynamicServerListLoadBalancer for client sources-service initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=sources-service,current list of Servers=[113.81.148.84:9090],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone;	Instance count:1;	Active connections count: 0;	Circuit breaker tripped count: 0;	Active connections per server: 0.0;]
},Server stats: [[Server:113.81.148.84:9090;	Zone:defaultZone;	Total Requests:0;	Successive connection failure:0;	Total blackout seconds:0;	Last connection made:Thu Jan 01 08:00:00 CST 1970;	First connection made: Thu Jan 01 08:00:00 CST 1970;	Active Connections:0;	total failure count in last (1000) msecs:0;	average resp time:0.0;	90 percentile resp time:0.0;	95 percentile resp time:0.0;	min resp time:0.0;	max resp time:0.0;	stddev resp time:0.0]
]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@1e324096
2019-01-10 09:58:08.193  INFO 20856 --- [erListUpdater-0] c.netflix.config.ChainedDynamicProperty  : Flipping property: sources-service.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 2147483647

1.1.2.关键错误信息:

Caused by: java.net.UnknownHostException: standalone: Name or service not known
这里可以可以知道 standalone 这个微服务并没有找到。

再看zuul中控制台日志
{NFLoadBalancer:name=sources-service,current list of Servers=[113.81.148.84:9090],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:1; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
发现是有他是能找到微服务的,地址也有,但是还是提示没有微服务,那么应该还是之前ip不对的问题。

1.1.3.解决办法:

这问题跟前几天的问题类似,就是注册中心服务名的实例对应的IP地址有误,现在来说明一下,那就是我一共有四个微服务,分别为 eureka注册中心、zuul路由、uaa-service授权中心、resource-service资源端。
当我让zuul 作为后端微服务的唯一入口,访问的是 zuul这个微服务的端口后,然后通过路由转发到uaa-service 和resource-service,上面的错误是在我使用zuul路由转发到resource过程中,出现了找不到微服务ip的问题,在网上针对报错的日志,说到了两个点:

  • (1)第一个点那么就是 eureka没有开启相互注册,这样的话吗,zuul就不能 从eureka获取服务的列表。对应的解决办法就是开启下面这两个设置:
    registry 和 register-with-eureka 这两个参数分别设置为 true;配置详细如下。
    针对这个点,对项目中的代码进行了修改,发现还是找不到对应的实例。
eureka:
 client:
   serviceUrl:
     defaultZone: http://120.79.82.72:8761/eureka/
fetch-registry: true
   register-with-eureka: true
  • (2)另外一个说法就是IP地址的问题,在上面的log中都是可以找到对应的地址的,但是上面写的是 公网地址,而此时,zuul路由到resource-service的时候,两个微服务都是在爱本地跑的,他们的ip地址是对应内网的地址,直接写成上面的公网地址是访问不到的,(关于这点,内网公网这一块的知识还是很欠缺的),所以解决办法就是将注册到eureka的ip地址 改为 localhost。

综上是可以解决对应的报错信息的,但是又有了一个新的信息,报错信息如下。其实这个问题的根源就是请求头携带的 authorization 被过滤掉了,这是zuul自带的特性,这点就是昨天已经说过的点,所以这里不单独解决,直接在项目上,加上一个过滤器,完善过滤规则,并将 authorization 重写入请求头中。

1.1.2.Spring Cloud Zuul Filter

1.1.2.1.Filter

要想实现Filter,需要以下几个步骤:

  • 1.首先是集成 ZuulFilter类,通过继承ZuulFilter然后覆写下面的4个方法,这样就可以实现一个简单的过滤器。
  • 2.主类中,先开启前面的过滤器。
  • 3.输入请求,测试。

1.1.2.2.继承ZuulFilter类

这里就是直接写一个过滤器,然后我将其与项目结合,代码如下 :

/**
* @program: morepineapple
* @description: 过滤器
* @author: Mr.huang
* @create: 2019-01-10 10:57
**/
@Component
public class MyFilter extends ZuulFilter {

  @Autowired
  public RedisService redisService;

  private static Logger log = LoggerFactory.getLogger(MyFilter.class);

  @Override
  public String filterType() {
     // 前置过滤器
     return "pre";
  }

  @Override
  public int filterOrder() {
     // 优先级为0,数字越大,优先级越低
     return 0;
  }

  @Override
  public boolean shouldFilter() {
     // 是否执行该过滤器,此处为true,说明需要过滤
     return true;
  }

  /**
   * @Description 拦截器详细
   * @param []
   * @return java.lang.Object
   * @author Mr.HUANG
   * @date 2019/1/10
   * @throws ZuulException
   */
  @Override
  public Object run() throws ZuulException {
     // 获取共享上下文信息
     RequestContext ctx = RequestContext.getCurrentContext();
     HttpServletRequest request = ctx.getRequest();
     log.info(String.format("%s >>> %s", request.getMethod(), request.getRequestURL().toString()));

     String url = request.getRequestURI();
     log.info("当前请求url:{}",url);

     String loginOutPartUrl = "/a/out";
     String backstageUrlHead = "a";
     String loginPartUrl = "/a/login";

     // 登录及访问模块
     if (url.contains(backstageUrlHead) && !url.equals(loginPartUrl)){
        String accessToken = request.getHeader("Authorization");
        log.info("登录、访问模块authorization 获取:{}",accessToken);

        // accessTokennull
        if (StringUtils.isBlank(accessToken)){
           log.warn("accessToken is empty");
           ctx.setResponseBody("{\"code\": 2006, \"message\": \"token is empty\"}");
           return null;
        }
        // accessToken不为null
        else if (StringUtils.isNotBlank(accessToken)){
           Long loginTime = Long.valueOf(redisService.get(accessToken));
           Long nowTime = System.currentTimeMillis();
           Long timeOut = 3*24*60*60L;

           // 超过有效期
           if (0 ==loginTime || nowTime - loginTime > timeOut ){
              log.warn("token已过期");
              ctx.setResponseBody("{\"code\": 2007, \"message\": \"token is expired\"}");
              return null;
           }
        }
        ctx.addZuulRequestHeader("Authorization", "Bearer " + accessToken);
     }

     // 登出模块,直接补上 authorization,在服务类中再对以登录信息做处理
     if(url.contains(loginOutPartUrl)){
        String accessToken = request.getHeader("Authorization");
        ctx.addZuulRequestHeader("Authorization", "Bearer " + accessToken);
        return null;

     }


        // 登录模块也加入 accesstoken,但这个是客户端的信息      if(url.contains(loginPartUrl)){
        String accessToken = request.getHeader("Authorization");
        ctx.addZuulRequestHeader("Authorization", "Bearer " + accessToken);
        System.out.println("accessToken:" + accessToken );
        return null;
     }
     return null;
  }

}

因为zuul在昨天已经完成了一部分,加上这个过滤器,已经算完成,但是遇到了一些报错。

  • 报错一:提示需要权限

  • 问题分析:

  • 按照提示的意思即使说这个接口的访问是需要权限的信息的,然而我提交的内容里面并没有 authorization,所以报错了。


  • 解决办法:

  • 在springsecurity中将这个登录接口与设置为不需要权限信息即可访问。设置如下 :

  • 报错二:
    postman的返回结果信息如下:
    将日志输出转换为debug,查看控制台日志如下:

  • 2019-01-11 00:13:04.663 DEBUG 21056 --- [http-nio-9090-exec-6] o.s.boot.actuate.audit.listener.AuditListener                          : AuditEvent [timestamp=2019-01-10T16:13:04.663Z, principal=access-token, type=AUTHENTICATION_FAILURE, data={type=org.springframework.security.authentication.BadCredentialsException, message=Cannot convert access token to JSON}]
    2019-01-11 00:13:04.666 DEBUG 21056 --- [http-nio-9090-exec-6] o.s.security.web.header.writers.HstsHeaderWriter                       : Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@64132b53
    2019-01-11 00:13:04.668 DEBUG 21056 --- [http-nio-9090-exec-6] o.s.s.o.p.error.DefaultOAuth2ExceptionRenderer                         : Written [error="invalid_token", error_description="Cannot convert access token to JSON"] as "application/json;charset=UTF-8" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@eb68d2f]
    2019-01-11 00:13:04.669 DEBUG 21056 --- [http-nio-9090-exec-6] o.s.s.web.context.SecurityContextPersistenceFilter                     : SecurityContextHolder now cleared, as request processing completed


  • 这个问题暂未解决。

2.明天计划的事情

2.1.解决accesstoken转换格式问题。
2.2.优化过滤器逻辑,总感觉有点问题。
2.3.整合前面代码。

3.遇到的问题

3.1.accesstoken格式转换问题。



返回列表 返回列表
评论

    分享到