我们正在从 Java 8 迁移到 Java 11,从而从 Spring Boot 1.5.6 迁移到 2.1.2。我们注意到,在使用 RestTemplate 时,“+”号不再编码为“%2B”(由 SPR-14828 更改)。这没关系,因为 RFC3986 没有将“+”列为保留字符,但在 Spring Boot 端点中接收时仍将其解释为“”(空格)。
我们有一个搜索查询,它可以将可选的时间戳作为查询参数。该查询类似于 http://example.com/search?beforeTimestamp=2019-01-21T14:56:50%2B00:00。
如果不进行双重编码,我们无法弄清楚如何发送编码的加号。查询参数 2019-01-21T14:56:50+00:00 将被解释为 2019-01-21T14:56:50 00:00。如果我们自己对参数进行编码(2019-01-21T14:56:50%2B00:00),那么它将被接收并解释为 2019-01-21T14:56: 50%252B00:00.
另一个约束是,我们希望在设置 restTemplate 时在别处设置基本 url,而不是在执行查询的位置。
或者,有没有办法强制“+”不被端点解释为“”?
我写了一个简短的例子,展示了一些实现更严格编码的方法,并在注释中解释了它们的缺点:
package com.example.clientandserver;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.DefaultUriBuilderFactory;
import org.springframework.web.util.UriComponentsBuilder;
import org.springframework.web.util.UriUtils;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
@SpringBootApplication
@RestController
public class ClientAndServerApp implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(ClientAndServerApp.class, args);
}
@Override
public void run(String... args) {
String beforeTimestamp = "2019-01-21T14:56:50+00:00";
// Previously - base url and raw params (encoded automatically).
// This worked in the earlier version of Spring Boot
{
RestTemplate restTemplate = new RestTemplateBuilder()
.rootUri("http://localhost:8080").build();
UriComponentsBuilder b = UriComponentsBuilder.fromPath("/search");
if (beforeTimestamp != null) {
b.queryParam("beforeTimestamp", beforeTimestamp);
}
restTemplate.getForEntity(b.toUriString(), Object.class);
// Received: 2019-01-21T14:56:50 00:00
// Plus sign missing here ^
}
// Option 1 - no base url and encoding the param ourselves.
{
RestTemplate restTemplate = new RestTemplate();
UriComponentsBuilder b = UriComponentsBuilder
.fromHttpUrl("http://localhost:8080/search");
if (beforeTimestamp != null) {
b.queryParam(
"beforeTimestamp",
UriUtils.encode(beforeTimestamp, StandardCharsets.UTF_8)
);
}
restTemplate.getForEntity(
b.build(true).toUri(), Object.class
).getBody();
// Received: 2019-01-21T14:56:50+00:00
}
// Option 2 - with templated base url, query parameter is not optional.
{
RestTemplate restTemplate = new RestTemplateBuilder()
.rootUri("http://localhost:8080")
.uriTemplateHandler(new DefaultUriBuilderFactory())
.build();
Map<String, String> params = new HashMap<>();
params.put("beforeTimestamp", beforeTimestamp);
restTemplate.getForEntity(
"/search?beforeTimestamp={beforeTimestamp}",
Object.class,
params);
// Received: 2019-01-21T14:56:50+00:00
}
}
@GetMapping("/search")
public void search(@RequestParam String beforeTimestamp) {
System.out.println("Received: " + beforeTimestamp);
}
}
最佳答案
我们意识到在编码完成后可以在拦截器中修改 URL。所以一个解决方案是使用一个拦截器,它对查询参数中的加号进行编码。
RestTemplate restTemplate = new RestTemplateBuilder()
.rootUri("http://localhost:8080")
.interceptors(new PlusEncoderInterceptor())
.build();
一个简短的例子:
public class PlusEncoderInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
return execution.execute(new HttpRequestWrapper(request) {
@Override
public URI getURI() {
URI u = super.getURI();
String strictlyEscapedQuery = StringUtils.replace(u.getRawQuery(), "+", "%2B");
return UriComponentsBuilder.fromUri(u)
.replaceQuery(strictlyEscapedQuery)
.build(true).toUri();
}
}, body);
}
}
关于java - '+' (plus sign) not encoded with RestTemplate using String url, but interpreted as ''(空格),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54294843/
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳
我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request