我试图创建微服务,但zuul api网关服务maped错误的网址。似乎它与编码问题有关。
Zuul application.properties
spring.application.name=zuul-api-gateway
server.port=8765
eureka.client.service-url.default-zone=http://localhost:8761/eureka
服务application.yml
spring:
application:
name: car-service
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3307/car_service_db?useSSL=false
username: root
password: admin
profiles:
active: local
server:
port: 8080
eureka:
client:
service-url:
default-zone: http://localhost:8761/eureka
management:
security:
enabled: false
其他服务application.yml
spring:
application:
name: company-service
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3307/company_service_db?useSSL=false
username: root
password: admin
server:
port: 8081
eureka:
client:
service-url:
default-zone: http://localhost:8761/eureka
management:
security:
enabled: false
尤里卡日志:
2018-02-11 00:02:41.204 INFO 22672 --- [nio-8761-exec-2] c.n.e.registry.AbstractInstanceRegistry : Registered instance CAR-SERVICE/localhost:car-service:8080 with status UP (replication=false)
2018-02-11 00:02:58.469 INFO 22672 --- [a-EvictionTimer] c.n.e.registry.AbstractInstanceRegistry : Running the evict task with compensationTime 0ms
2018-02-11 00:03:06.468 INFO 22672 --- [nio-8761-exec-4] c.n.e.registry.AbstractInstanceRegistry : Registered instance COMPANY-SERVICE/localhost:company-service:8081 with status UP (replication=false)
2018-02-11 00:03:26.139 INFO 22672 --- [nio-8761-exec-9] c.n.e.registry.AbstractInstanceRegistry : Registered instance ZUUL-API-GATEWAY/localhost:zuul-api-gateway:8765 with status UP (replication=false)
和zuul日志
2018-02-11 00:03:35.037 INFO [zuul-api-gateway,6944cfba5180a640,6944cfba5180a640,false] 2132 --- [nio-8765-exec-1] o.s.c.n.zuul.web.ZuulHandlerMapping : Mapped URL path [/car-servıce/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
2018-02-11 00:05:06.872 INFO [zuul-api-gateway,773aa5fc779af5e6,773aa5fc779af5e6,false] 2132 --- [nio-8765-exec-3] o.s.c.n.zuul.web.ZuulHandlerMapping : Mapped URL path [/company-servıce/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
2018-02-11 00:05:06.873 INFO [zuul-api-gateway,773aa5fc779af5e6,773aa5fc779af5e6,false] 2132 --- [nio-8765-exec-3] o.s.c.n.zuul.web.ZuulHandlerMapping : Mapped URL path [/zuul-apı-gateway/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]
在zuul日志中,所有服务都用特殊字母和'ı'映射,这是土耳其字符而不是'i',我无法通过zuul api网关到达我的服务。
我在这个例子中也试过覆盖Zuul配置:Spring-Cloud Zuul breaks UTF-8 symbols in forwarded multipart request filename
@Configuration
public class WebConfig extends WebMvcConfigurerAdapter {
@Bean
FormBodyWrapperFilter formBodyWrapperFilter() {
return new FormBodyWrapperFilter(new MyFormHttpMessageConverter());
}
private class MyFormHttpMessageConverter extends FormHttpMessageConverter {
private byte[] getAsciiBytes(String name) {
try {
// THIS IS THE ONLY MODIFICATION:
return name.getBytes("UTF-8");
} catch (UnsupportedEncodingException ex) {
// Should not happen - US-ASCII is always supported.
throw new IllegalStateException(ex);
}
}
}
}
因此,当我通过Zuul api网关尝试呼叫服务时,它返回404未找到。
我使用spring-boot 2.0.0.M3,spring-cloud Finchley.M2版本
当你使用Spring启动时,我建议你为zuul网关使用注释,并为zuul创建自定义过滤器,它将照顾每一件事。
请找到下面的代码,看看它是否适合您:
主类
@EnableZuulProxy
@SpringBootApplication
@EnableScheduling
@EnableFeignClients(basePackages = { Constants.FEIGN_BASE_PACKAGE })
@ComponentScan(basePackages = { Constants.BASE_PACKAGE, Constants.LOGGING_PACKAGE })
@EntityScan(basePackages = { Constants.ENTITY_BASE_PACKAGE })
@EnableDiscoveryClient
public class GatewayInitializer {
/**
* The main method.
*
* @param args the arguments
*/
public static void main(String[] args) {
Security.setProperty("networkaddress.cache.ttl", "30");
ConfigurableApplicationContext context = SpringApplication.run(Initializer.class, args);
}
ZUUL过滤器
package com.sxm.aota.gateway.filters;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.util.ReflectionUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
/**
* This CustomErrorFilter involve to handle ZuulException.
*/
public class CustomErrorFilter extends ZuulFilter {
/** The logger. */
private static final Logger logger = LoggerFactory.getLogger(CustomErrorFilter.class);
/** The message source. */
@Autowired
private MessageSource messageSource;
/** The properties. */
@Autowired
private Properties properties;
/*
* (non-Javadoc)
*
* @see com.netflix.zuul.ZuulFilter#filterType()
*/
@Override
public String filterType() {
return "post";
}
/*
* (non-Javadoc)
*
* @see com.netflix.zuul.ZuulFilter#filterOrder()
*/
@Override
public int filterOrder() {
return -1; // Needs to run before SendErrorFilter which has filterOrder == 0
}
/*
* (non-Javadoc)
*
* @see com.netflix.zuul.IZuulFilter#shouldFilter()
*/
@Override
public boolean shouldFilter() {
// only forward to errorPath if it hasn't been forwarded to already
return RequestContext.getCurrentContext().containsKey("error.status_code");
}
/*
* (non-Javadoc)
*
* @see com.netflix.zuul.IZuulFilter#run()
*/
@Override
public Object run() {
try {
RequestContext ctx = RequestContext.getCurrentContext();
Object e = ctx.get("error.exception");
if (e != null && e instanceof ZuulException) {
ZuulException zuulException = (ZuulException) e;
logger.error("Zuul failure detected: " + zuulException.getMessage(), zuulException);
// Remove error code to prevent further error handling in follow up filters
ctx.remove("error.status_code");
} else {
error.setMessage(messageSource.getMessage(Constants.REQUESTED_SERVICE_UNAVAILABLE, new Object[] { zuulException.getCause() }, properties.getCurrentLocale()));
ctx.setResponseBody(mapper.writeValueAsString(error));
ctx.getResponse().setContentType("application/json");
ctx.setResponseStatusCode(500); // Can set any error code as excepted
}
}
} catch (Exception ex) {
logger.error("Exception filtering in custom error filter", ex);
ReflectionUtils.rethrowRuntimeException(ex);
}
return null;
}
}
我通过为toLowerCase(Locale.ROOT)选项创建扩展的EurekaDiscoveryClient来解决问题。
import com.netflix.appinfo.EurekaInstanceConfig;
import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.shared.Application;
import com.netflix.discovery.shared.Applications;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient;
import org.springframework.stereotype.Component;
import java.util.*;
@Component
public class CustomEurekaDiscoveryClient extends EurekaDiscoveryClient implements DiscoveryClient {
private final EurekaInstanceConfig config;
private final EurekaClient eurekaClient;
public CustomEurekaDiscoveryClient(EurekaInstanceConfig config, @Qualifier("eurekaClient") EurekaClient eurekaClient) {
super(config, eurekaClient);
this.config = config;
this.eurekaClient = eurekaClient;
}
@Override
public List<String> getServices() {
Applications applications = this.eurekaClient.getApplications();
if (applications == null) {
return Collections.emptyList();
}
List<Application> registered = applications.getRegisteredApplications();
List<String> names = new ArrayList<>();
for (Application app : registered) {
if (app.getInstances().isEmpty()) {
continue;
}
names.add(app.getName().toLowerCase(Locale.ROOT));
}
return names;
}
}
大写'I'在土耳其语OS和jvm中转换为小写'ı'而不是'i',这就是我需要覆盖公共List getServices()方法的原因。
如果toLowerCase(Locale.ROOT)方法调用没有Locale.ROOT java转换字符为'ı'但使用Locale.ROOT选项,方法转换为'i'并且项目工作正常。
您可以在main方法中为英语添加Locale.setDefault。
public static void main(String[] args) {
Locale.setDefault(new Locale("en", "US"));
SpringApplication.run(ServerApplication.class, args);
}
它也解决了你的问题。