Open Joker-Q4 opened 2 months ago
builder.build()
.post()
.uri(uriBuilder -> {
URI build = uriBuilder
.path("/serviceValidate")
.queryParam("ticket", ticket)
.queryParam("service", service)
.queryParam("pgtUrl", pgtUrl)
.queryParam("renew", renew)
.build();
log.info("url: {}", build);
return build;
})
.retrieve()
.bodyToMono(String.class)
.retry(3)
.doOnError(throwable -> {
ExceptionUtil.printStackTrace(throwable);
});
添加了也不行
我也遇到了同样的问题,使用的是spring-boot-starter-webflux 和 sa-token-reactor-spring-boot3-starter 1.39.0
/**
* 在当前线程的 SaRequest 包装对象
*
* @return /
*/
public static SaRequest getRequest() {
return getBoxNotNull().getRequest();
}
/**
* 在当前线程的 SaResponse 包装对象
*
* @return /
*/
public static SaResponse getResponse() {
return getBoxNotNull().getResponse();
}
/**
* 在当前线程的 SaStorage 存储器包装对象
*
* @return /
*/
public static SaStorage getStorage() {
return getBoxNotNull().getStorage();
}
我发现http请求中进行StpUtil.login()时,会调用两次getRequest,调用一次getStorage,其中在getStorage()时,报错:未能获取有效的上下文
分析源码发现box的初始化发生在此处:
SaReactorSyncHolder:
public static void setContext(ServerWebExchange exchange) { SaRequest request = new SaRequestForReactor(exchange.getRequest()); SaResponse response = new SaResponseForReactor(exchange.getResponse()); SaStorage storage = new SaStorageForReactor(exchange); SaTokenContextForThreadLocalStorage.setBox(request, response, storage); }
SaTokenContextForThreadLocalStorage中:
/** * 基于 ThreadLocal 的 [ Box 存储器 ] */ public static ThreadLocal<Box> boxThreadLocal = new InheritableThreadLocal<>();
/**
* 初始化当前线程的 [ Box 存储器 ]
* @param request {@link SaRequest}
* @param response {@link SaResponse}
* @param storage {@link SaStorage}
*/
public static void setBox(SaRequest request, SaResponse response, SaStorage storage) {
Box bok = new Box(request, response, storage);
boxThreadLocal.set(bok);
}
两次getRequest使用的是同一个box,而getStorage重新初始化了一个box,也就是重新调用了setContext方法(setContext时,box是初始化成功的了,但是在getBoxNotNull时,拿到的为null)
执行过程中其实SaSession已经创建好,并且在debug时也可以通过打印的token拿出来,但是在SaStorage storage = SaHolder.getStorage();时发生错误,我发获取storage
我不知道是否是因为getStorage前调用了setContext重新初始化box导致的
以下方法执行失败报错:未能获取有效的上下文
public Mono<Result> login(AccountDTO accountDTO) {
return Mono.just(accountDTO)
.flatMap(dto -> {
if (StrUtil.isNotBlank(dto.getMail())) {
return getByMail(dto.getMail());
} else if (StrUtil.isNotBlank(dto.getUsername())) {
return getByUsername(dto.getUsername());
} else {
return Mono.error(new ServiceException(CommonResultType.PARAMETER_ERROR));
}
})
.map(account -> {
StpUtil.login(account.getAccountId());
return Result.success(StpUtil.getSessionByLoginId(account.getAccountId()));
});
}
强制转化为阻塞式之后执行成功
public Mono<Result> login(AccountDTO accountDTO) {
return Mono.fromCallable(() -> {
if (StrUtil.isBlank(accountDTO.getPassword()) || StrUtil.isBlank(accountDTO.getMail())) {
return Result.fail(CommonResultType.PARAMETER_ERROR);
}
Account loginAccount = getByMail(accountDTO.getMail()).block();
StpUtil.login(loginAccount.getAccountId());
//登陆成功,返回token
return Result.success(StpUtil.getTokenInfo());
})
.subscribeOn(Schedulers.boundedElastic()) // 切换到 boundedElastic 线程池
;
}
两种写法,在执行getRequest和getStorage时都是不同的线程,但是不太清除为什么强制阻塞后可以执行成功
同样问题
spring-boot-starter-webflux,sa-token-reactor-spring-boot3-starter +1
https://github.com/dromara/Sa-Token/issues/506 参考着2个应该可以解决
使用版本:
1.38.0
涉及的功能模块:
gateway
测试步骤:
public static Box getBoxNotNull() { Box box = (Box)boxThreadLocal.get(); if (box == null) { throw (new SaTokenContextException("未能获取有效的上下文")).setCode(10002); } else { return box; } }
builder.build() .post() .uri(uriBuilder -> { URI build = uriBuilder .path("/serviceValidate") .queryParam("ticket", ticket) .queryParam("service", service) .queryParam("pgtUrl", pgtUrl) .queryParam("renew", renew) .build(); log.info("url: {}", build); return build; }) .retrieve() .bodyToMono(String.class)