RestTemplate发送http请求时,get方式携带参数的特殊字符编码问题记录

项目中使用RestTemplate发送HTTP请求,get方式url拼接参数结果不符。经分析,是RestTemplate发送string类型参数时对url编码,导致实际参数与预期不同。给出两种解决方案,一是传URI类型参数,二是先解码参数再发送请求,推荐方案一。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:

项目中需要对接其他项目-使用RestTemplate发送http请求;
get方式url后拼接参数方式与预期结果不符;

工具类代码如下:

/**
     * 发送get请求
     *
     * @param url
     * @param params
     * @param header
     * @return
     */
    public static String getHttplient(String url, Map<String, Object> params, Map<String, String> header) {
        HttpHeaders headers = new HttpHeaders();
        if (!CollectionUtils.isEmpty(header)) {
            // 填充header
            for (Map.Entry<String, String> entry : header.entrySet()) {
                headers.add(entry.getKey(), entry.getValue());
            }
        }
        HttpEntity<Map<String, Object>> entry = new HttpEntity<>(params, headers);
        log.info("流水号:{},调用外部接口,url:{},参数:{},header:{}", TLocalHelper.getSeq(), url, JsonUtil.toJsonString(params), header);
        ResponseEntity<String> result = restTemplate.getForEntity(url, String.class, params);
        log.info("流水号:{},返回结果:{}", TLocalHelper.getSeq(), result.getBody());
        return result.getBody();
    }

首先:
确定对方提供接口以及测试参数无误:
在这里插入图片描述
然后:
工具类代码如下:

@Test
    public void test111() throws Exception {

        String token = "cUJ%2FFaFkoEVx5XNRGCm1ZivqNoJqhyuQQL6GhywoMKusSAHujQsoUMWnKgjBFp3L";

        String url = tokenUrl + "?token=" + token;
        String s = HttpUtil.getHttplient(url, new HashMap<>(), new HashMap<>());
    }

tokenUrl是从配置文件中加载的;
运行结果:
在这里插入图片描述

- 对比分析:

工具类发送的url地址和在浏览器里输入的地址,完全一致,但是一个成功,一个失败;
那么:问题定位:工具类的问题
在查询了一些资料和源码发现:
在这里插入图片描述

RestTemplate在发送string类型的参数请求时,将url给encode了;那么就造成了实际上发送的url参数和我们放进去的值不一样;所以造成了错误;

同时我们也发现:
在发送URI类型的参数请求时,是直接发送的,
那此时,我们应该有两种方案去解决此问题:

  1. 通过传URI类型的参数方式实现;(推荐此方案)
  2. 在发送请求前;先将我们的参数decode掉,这样,保证发送的请求经过底层的encode时,不会多次encode,以引发实际上发送的url参数和我们放进去的值不一样;(此方案可能存在bug,所以推荐方案一)

解决方案一: 通过传URI类型的参数方式实现;

添加工具类方法(通过URI方式传参):

public static String getHttplienturi(URI url, Map<String, Object> params, Map<String, String> header) {
        HttpHeaders headers = new HttpHeaders();
        if (!CollectionUtils.isEmpty(header)) {
            // 填充header
            for (Map.Entry<String, String> entry : header.entrySet()) {
                headers.add(entry.getKey(), entry.getValue());
            }
        }
        HttpEntity<Map<String, Object>> entry = new HttpEntity<>(params, headers);
        log.info("流水号:{},调用外部接口,url:{},参数:{},header:{}", TLocalHelper.getSeq(), url, JsonUtil.toJsonString(params), header);
        String result = restTemplate.getForObject(url, String.class);
        log.info("流水号:{},返回结果:{}", TLocalHelper.getSeq(), result);
        return result;
    }

调用代码:
使用UriComponentBuilder构造URI对象

@Test
    public void test111() throws Exception {

        String token = "cUJ%2FFaFkoEVx5XNRGCm1ZivqNoJqhyuQQL6GhywoMKusSAHujQsoUMWnKgjBFp3L";

        UriComponentsBuilder builder = UriComponentsBuilder
                .fromHttpUrl(tokenUrl).queryParam("token", token);
        URI uri =  builder.build(true).toUri();
        String s = HttpUtil.getHttplienturi(uri, new HashMap<>(),new HashMap<>());
    }

结果:
在这里插入图片描述
完美解决;

解决方案二: 先将我们的参数decode,再发送请求;

代码如下:

@Test
    public void test111() throws Exception {

        String token = "cUJ%2FFaFkoEVx5XNRGCm1ZivqNoJqhyuQQL6GhywoMKusSAHujQsoUMWnKgjBFp3L";

        token = URLDecoder.decode(token,"UTF-8");

        String url = tokenUrl + "?token=" + token;
        String s = HttpUtil.getHttplient(url, new HashMap<>(), new HashMap<>());
    }

结果:
在这里插入图片描述
注意:
在查询文档时,发现有人用此方案仍然无法解决,但是我这边没有出现此问题,所以没有记录;
推荐使用方案一;此方案留做记录;

PS:
另外:
我个人觉得,其实对方设计的此种方案并不是太合理;
像这种问题,只会在get方式请求,并且参数是通过url拼接方式传递才会出现;
在一开始设计时,设计成通过post方式请求,application/json方式携带参数,可完美避免此问题;

但是,
我们接对方接口,不能出现问题就要求对方修改代码,这是不现实的,我们也要可以通过修改自己代码的方案来解决bug;

### 修改苍穹外卖项目中前端的OSS配置 为了确保前端能够正常显示从阿里云OSS获取的图片资源,需调整OSS存储权限以及相应前端配置。 #### 调整OSS存储桶访问权限 由于初始设置可能为私有模式,这会阻止前端直接加载图像。应将存储桶权限更改为公共读取模式以便于前端顺利展示图片[^2]。具体操作如下: 1. 登录至阿里云官网并进入对象存储OSS管理界面[^3]; 2. 找到对应的Bucket名称,并点击进入详情页; 3. 在左侧菜单栏找到“权限管理”,将其设为“公共读”。 #### 更新前端应用中的OSS配置项 对于前端部分而言,通常会在环境变量文件或是专门负责处理媒体资源请求的服务模块内定义好连接参数。假设当前使用的是一套基于Vue.js框架构建的应用程序,则可以在`.env`系列文件里指定必要的属性;如果采用React或其他技术栈,逻辑相似只是路径不同而已。 以下是针对Vue CLI项目的实例说明,在根目录下的`.env.development.local`或`.env.production.local`等环境中添加/修改以下键值对: ```bash VUE_APP_OSS_BUCKET_NAME=your-bucket-name VUE_APP_OSS_REGION=oss-cn-hangzhou # 替换成实际区域代码 VUE_APP_OSS_DOMAIN=https://your-bucket-name.oss-cn-hangzhou.aliyuncs.com/ ``` 另外还需注意的是,当涉及到跨域资源共享(CORS)问题,也需要适当放宽策略允许特定源发起GET请求以获取静态资源。同样是在上述提到的对象存储控制面板内的CORS规则处完成设定。 最后一步就是在涉及图片渲染的地方利用新加入的域名拼接出完整的URL地址供HTML img标签src属性使用。 通过以上更改可以解决因权限不足而导致的前端无法预览来自OSS上的图片的问题
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值