HTTPClient

HttpClient 的作用,就是让你的后端程序在运行时,主动去调用别的 Web 接口(HTTP 服务)。

比如在“苍穹外卖”Day6里,你的后端需要拿着微信小程序传来的 code 去访问微信官方的接口:

https://api.weixin.qq.com/sns/jscode2session?appid=xxx&secret=xxx&js_code=xxx

这里微信的接口在互联网上,它不是你自己写的。
所以你需要一个工具来 发起HTTP请求,拿到微信返回的数据(openid等)。

HttpClient 就是干这件事的工具。

发起方 对象 说明
前端(小程序) 访问你的服务端接口 比如 /user/login
后端(你的Spring项目) 访问微信官方接口 用 HttpClient 调用微信的API

核心API

  • HttpClient:Http客户端对象类型,使用该类型对象可发起Http请求。
  • HttpClients:可认为是构建器,可创建HttpClient对象。
  • CloseableHttpClient:实现类,实现了HttpClient接口。
  • HttpGet:Get方式请求类型。
  • HttpPost:Post方式请求类型。

注意:外卖中讲httpclient封装为了工具类,这里不过多赘述。

微信登录流程

  • 先在小程序端 使用wx.login() 获得code 授权码
  • 小程序端 wx.request 携带code 发送请求到后台
  • 后台收到code后, 携带 appid + appSecret + code 使用HttpClient 发送到微信的登入接口服务
  • 接口返回一些数据给后台,最重要的是openid 这是微信用户的唯一身份标识
  • 后台 自定义登入状态, 生成token,加上openid等数据发送给小程序
  • 小程序存储下这些数据,以后发起请求的时候携带token进行身份验证
  • 后端收到请求 验证token后在进行业务处理



Controller层(调用service层获取user并返回令牌)

 @PostMapping("/login")
    public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO){
        User user=userService.login(userLoginDTO.getCode());
        //jwt
        Map<String,Object> claims = new HashMap<>();
        claims.put(JwtClaimsConstant.USER_ID,user.getId());
        String token = JwtUtil.createJWT(jwtProperties.getUserSecretKey(),jwtProperties.getUserTtl(),claims);
        log.info("用户登入成功,token为: {}",token);
        UserLoginVO userLoginVO = UserLoginVO.builder()
                .id(user.getId())
                .openid(user.getOpenid())
                .token(token)
                .build();
        return Result.success(userLoginVO);
    }

Service

public static final String WX_LOGIN = "https://api.weixin.qq.com/sns/jscode2session";
    @Override
    public User login(String code) {
        //拿到openid 是微信用户的唯一标识
        String openId = getOpenId(code);

        if(openId==null) throw new LoginFailedException(MessageConstant.LOGIN_FAILED);

        //需要判定当前用户是否为新用户,新用户才需要插入数据库
        User user = userMapper.getByOpenid(openId);
        if(user==null){
            user = User.builder()
                    .openid(openId)
                    .createTime(LocalDateTime.now())
                    .build();
            userMapper.insert(user);
        }

        return user;
    }

    private String getOpenId(String code) {
        Map<String,String> map = new HashMap<>();
        map.put("appid",weChatProperties.getAppid());
        map.put("secret",weChatProperties.getSecret());
        map.put("js_code",code);
        map.put("grant_type","authorization_code");
        String json = HttpClientUtil.doGet(WX_LOGIN,map);
        return JSON.parseObject(json).getString("openid");
    }

拦截器

@Component
@Slf4j
public class JwtTokenUserInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtProperties jwtProperties;

    /**
     * 校验jwt
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //判断当前拦截到的是Controller的方法还是其他资源
        if (!(handler instanceof HandlerMethod)) {
            //当前拦截到的不是动态方法,直接放行
            return true;
        }

        //1、从请求头中获取令牌
        String token = request.getHeader(jwtProperties.getUserTokenName());

        //2、校验令牌
        try {
            log.info("jwt校验:{}", token);
            Claims claims = JwtUtil.parseJWT(jwtProperties.getUserSecretKey(), token);
            Long userId = Long.valueOf(claims.get(JwtClaimsConstant.USER_ID).toString());
            log.info("当前用户id:{}", userId);
            //Done 存放当前用户ID到ThreadLocal中
            BaseContext.setCurrentId(userId);
            //3、通过,放行
            return true;
        } catch (Exception ex) {
            //4、不通过,响应401状态码
            response.setStatus(401);
            return false;
        }
    }
}

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐