发表于: 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);
// accessToken为null
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格式转换问题。
评论