@FeignClient(value = "uaa", configuration = OauthFeignClient.Conf.class)
public interface OauthFeignClient {
@RequestMapping(
value = "/oauth/token",
method = RequestMethod.POST,
consumes = MULTIPART_FORM_DATA_VALUE,
produces = APPLICATION_JSON_VALUE)
ResponseEntity<OauthTokenResponse> token(Map<String, ?> formParams);
class Conf {
@Value("${oauth.client.password}")
String oauthClientPassword;
@Bean
public Encoder feignFormEncoder() {
return new SpringFormEncoder();
}
@Bean
public Contract feignContract() {
return new SpringMvcContract();
}
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("web-client", oauthClientPassword);
}
}
}
@PostMapping("/login")
public ResponseEntity<LoginTokenPair> getTokens(@RequestBody @Valid LoginRequest userCredentials) {
Map<String, String> formData = new HashMap<>();
ResponseEntity<OauthTokenResponse> response = oauthFeignClient.token(formData);
//code never reached if contacted service returns a 400
...
}
顺便说一下,我之前给出的解决方案是可行的,但我的初衷是坏主意:错误就是错误,不应该在标称流上处理。抛出一个异常(如Feign所做的),并使用@exceptionhandler
处理它是Spring MVC世界中更好的方法。
所以有两种解决方案:
FeignException
@ExceptionHandler
ErrorDecoder
配置FeignClient
以转换业务层知道的异常中的错误(并且已经为其提供了@ExceptionHandler
)@FeignClient(value = "uaa", configuration = OauthFeignClient.Config.class)
public interface OauthFeignClient {
@RequestMapping(
value = "/oauth/token",
method = RequestMethod.POST,
consumes = MULTIPART_FORM_DATA_VALUE,
produces = APPLICATION_JSON_VALUE)
DefaultOAuth2AccessToken token(Map<String, ?> formParams);
@Configuration
class Config {
@Value("${oauth.client.password}")
String oauthClientPassword;
@Autowired
private ObjectFactory<HttpMessageConverters> messageConverters;
@Bean
public Encoder feignFormEncoder() {
return new SpringFormEncoder(new SpringEncoder(messageConverters));
}
@Bean
public Decoder springDecoder() {
return new ResponseEntityDecoder(new SpringDecoder(messageConverters));
}
@Bean
public Contract feignContract() {
return new SpringMvcContract();
}
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("web-client", oauthClientPassword);
}
@Bean
public ErrorDecoder uaaErrorDecoder(Decoder decoder) {
return (methodKey, response) -> {
try {
OAuth2Exception uaaException = (OAuth2Exception) decoder.decode(response, OAuth2Exception.class);
return new SroException(
uaaException.getHttpErrorCode(),
uaaException.getOAuth2ErrorCode(),
Arrays.asList(uaaException.getSummary()));
} catch (Exception e) {
return new SroException(
response.status(),
"Authorization server responded with " + response.status() + " but failed to parse error payload",
Arrays.asList(e.getMessage()));
}
};
}
}
}
常见业务异常
public class SroException extends RuntimeException implements Serializable {
public final int status;
public final List<String> errors;
public SroException(final int status, final String message, final Collection<String> errors) {
super(message);
this.status = status;
this.errors = Collections.unmodifiableList(new ArrayList<>(errors));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SroException)) return false;
SroException sroException = (SroException) o;
return status == sroException.status &&
Objects.equals(super.getMessage(), sroException.getMessage()) &&
Objects.equals(errors, sroException.errors);
}
@Override
public int hashCode() {
return Objects.hash(status, super.getMessage(), errors);
}
}
错误处理程序(从ResponseEntityExceptionHandler
扩展中提取)
@ExceptionHandler({SroException.class})
public ResponseEntity<Object> handleSroException(SroException ex) {
return new SroError(ex).toResponse();
}
错误响应DTO
@XmlRootElement
public class SroError implements Serializable {
public final int status;
public final String message;
public final List<String> errors;
public SroError(final int status, final String message, final Collection<String> errors) {
this.status = status;
this.message = message;
this.errors = Collections.unmodifiableList(new ArrayList<>(errors));
}
public SroError(final SroException e) {
this.status = e.status;
this.message = e.getMessage();
this.errors = Collections.unmodifiableList(e.errors);
}
protected SroError() {
this.status = -1;
this.message = null;
this.errors = null;
}
public ResponseEntity<Object> toResponse() {
return new ResponseEntity(this, HttpStatus.valueOf(this.status));
}
public ResponseEntity<Object> toResponse(HttpHeaders headers) {
return new ResponseEntity(this, headers, HttpStatus.valueOf(this.status));
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof SroError)) return false;
SroError sroException = (SroError) o;
return status == sroException.status &&
Objects.equals(message, sroException.message) &&
Objects.equals(errors, sroException.errors);
}
@Override
public int hashCode() {
return Objects.hash(status, message, errors);
}
}
@RestController
@RequestMapping("/uaa")
public class AuthenticationController {
private static final BearerToken REVOCATION_TOKEN = new BearerToken("", 0L);
private final OauthFeignClient oauthFeignClient;
private final int refreshTokenValidity;
@Autowired
public AuthenticationController(
OauthFeignClient oauthFeignClient,
@Value("${oauth.ttl.refresh-token}") int refreshTokenValidity) {
this.oauthFeignClient = oauthFeignClient;
this.refreshTokenValidity = refreshTokenValidity;
}
@PostMapping("/login")
public ResponseEntity<LoginTokenPair> getTokens(@RequestBody @Valid LoginRequest userCredentials) {
Map<String, String> formData = new HashMap<>();
formData.put("grant_type", "password");
formData.put("client_id", "web-client");
formData.put("username", userCredentials.username);
formData.put("password", userCredentials.password);
formData.put("scope", "openid");
DefaultOAuth2AccessToken response = oauthFeignClient.token(formData);
return ResponseEntity.ok(new LoginTokenPair(
new BearerToken(response.getValue(), response.getExpiresIn()),
new BearerToken(response.getRefreshToken().getValue(), refreshTokenValidity)));
}
@PostMapping("/logout")
public ResponseEntity<LoginTokenPair> revokeTokens() {
return ResponseEntity
.ok(new LoginTokenPair(REVOCATION_TOKEN, REVOCATION_TOKEN));
}
@PostMapping("/refresh")
public ResponseEntity<BearerToken> refreshToken(@RequestHeader("refresh_token") String refresh_token) {
Map<String, String> formData = new HashMap<>();
formData.put("grant_type", "refresh_token");
formData.put("client_id", "web-client");
formData.put("refresh_token", refresh_token);
formData.put("scope", "openid");
DefaultOAuth2AccessToken response = oauthFeignClient.token(formData);
return ResponseEntity.ok(new BearerToken(response.getValue(), response.getExpiresIn()));
}
}
我有一个名为Backend(端口:9090)的服务,位于Zuul(端口:8080)后面。 浏览器在Zuul上调用GET方法,执行重定向。 示例调用:http://localhost:8080/testredirect 结果: 浏览器收到Http状态=200 浏览器URL:http://localhost:8080/testredirect 浏览器显示:Hello world 预期结果: 浏览器应接
下面是我正在使用的一段代码: 期望reponse conatins的状态行:“HTTP/1.1400坏请求”想知道这是可以实现的吗?如果是,那么我如何继续做同样的事情。
问题内容: 我试图按照此链接中的建议将错误返回到对控制器的调用,以便客户端可以采取适当的措施。javascript通过jqueryAJAX调用控制器。仅在不将状态设置为error的情况下,我才可以重新获得Json对象。这是示例代码 如果没有设置状态码,我会得到Json。如果设置状态代码,则会返回状态代码,但不会返回Json错误对象。 更新 我想将Error对象作为JSON发送,以便可以处理ajax
我正在使用java.net.HttpUrlConnection向我的服务器发出Http请求。我意识到如果服务器返回错误状态(例如 400)。HttpUrlConnection 将抛出与错误状态对应的 IOException。 我的问题是:如果服务器返回错误状态(4xx,5xx),HttpUrlConnection是否总是抛出IOException? 我看了一下HttpUrlConnection A
问题内容: 我在这我想从服务器获取与$ HTTP GET XML数据的AngularJS应用说http://example.com/a/b/c/d/getDetails?fname=abc&lname=def(此通过在浏览器中输入链接进行手动访问时显示XML文件的树状结构)。 当我运行应用程序时,不会从该链接获取数据。而是显示 状态为0 的错误。 我不确定$ http.get为什么会失败并转到返回
问题内容: 我正在使用 **java.net.HttpUrlConnection** 向我的服务器发出Http请求。我意识到,如果服务器返回错误状态(例如400)。HttpUrlConnection将抛出与错误状态相对应的IOException。 我的问题是: 如果服务器返回错误状态(4xx,5xx),HttpUrlConnection是否总是抛出IOException吗? 我看一下HttpUrl