我有一个 Java 客户端应用程序,它发送 REST 请求以从 REST 服务中检索一些数据。
我正在这样设置客户端:
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Response;
import org.glassfish.jersey.client.filter.EncodingFilter;
import org.glassfish.jersey.message.GZipEncoder;
SSLContext sslContext = SSLClientUtil.getSSLContext(getCertificate(keystore), keystorePassword);
this.client = ClientBuilder.newBuilder()
.sslContext(sslContext)
.hostnameVerifier(new TrustedHostnameVerifier())
.build();
client.register(GZipEncoder.class);
client.register(EncodingFilter.class);
this.webTarget = client.target("https://example.org:443/service/rest");
并在另一种方法中对服务器进行实际请求
//Get Method
Response response = this.webTarget.request().get()
// Extract the content
response.close();
// return the content
当我运行我的应用程序时,第一次运行 Get-Method 时,该服务返回响应,我得到了我的响应......但是在第一次运行之后。请求甚至没有发送到服务器(我在客户端的 eth 接口(interface)上看不到网络流量。
客户端似乎以某种方式缓存了响应并且不再发送请求。 我已经看到服务器发送带有 header Cache-Control: private 的响应。 我如何说服我的客户再次发送实际请求(如果)不使用任何缓存响应?
注意:我已经在我的客户端中尝试在 header 中设置缓存控制指令......但仍然没有使用该方法发送请求(this.webTarget.request().get())。
更新:
经过一些测试后,java 客户端应用程序作为 javaws 应用程序运行似乎有所作为。如果从调试器(没有 javaws)启动,则行为符合预期。将其作为 javaws 运行,请求被缓存。
这似乎类似于条目 here其中 javaws 应用程序正在使用缓存的 URLConnection
检索文档。那里的连接可以设置为不缓存。
jakarta.ws.rs/jersey 如何做到这一点?
最佳答案
概览
我试图重现你的问题并且
- 创建了一个简单的 Spring Boot 演示 REST 服务
它始终返回当前时间戳,因此缓存值等。 很容易识别。 - 启动 Spring Boot 演示应用程序
- 创建了一个使用 JAX-RS 和 Jersey 的 swing 演示客户端
- 编写了一个简单的 JNLP 文件
- 用gradle构建了一个fat jar
- (自己)在 fat jar 上签名
- 将 jnlp 文件复制到 build/libs 文件夹
- 切换到 build/libs 文件夹并通过
javaws Test.jnlp
启动
总结
我使用了来自 maven central 的最新 Jersey 依赖项。测试确实有效,每个请求调用确实从 REST 服务获取新数据(即使在服务器端启用了缓存)。我在 Linux 机器上使用 Java Webstart“icedtea-web 1.8 (1.8)”进行了测试。
也许你的库已经过时了,你应该像我的测试文件一样简单地更新你的依赖项?您可以简单地使用您的 javaws
安装尝试下面的示例并采用必要的部分。
如果示例确实也产生了您的问题,根本原因似乎是您的 webstart/Java 安装 - 也许更新会有所帮助。
来源
JaxRSTestApplication + Gradle 设置
plugins {
id 'java'
id 'java-library'
id 'eclipse'
}
group = 'com.example.demo'
version = '1.0.0'
sourceCompatibility = '11'
repositories {
mavenCentral()
}
dependencies {
implementation group: 'org.glassfish.jersey.core', name: 'jersey-client', version: '3.0.2'
implementation group: 'org.glassfish.jersey.inject', name: 'jersey-hk2', version: '3.0.2'
implementation group: 'jakarta.activation', name: 'jakarta.activation-api', version: '2.0.1'
}
task fatJar(type: Jar) {
archiveClassifier = 'fat'
duplicatesStrategy = 'exclude'
from sourceSets.main.output
manifest {
attributes 'Main-Class': 'com.example.demo.JaxRSTestApplication'
attributes 'Application-Name': 'JaxRSTestApplication'
}
dependsOn configurations.runtimeClasspath
from {
configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) }
}
}
package com.example.demo;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import org.glassfish.jersey.client.filter.EncodingFilter;
import org.glassfish.jersey.message.GZipEncoder;
import jakarta.ws.rs.client.Client;
import jakarta.ws.rs.client.ClientBuilder;
import jakarta.ws.rs.client.WebTarget;
import jakarta.ws.rs.core.Response;
public class JaxRSTestApplication {
private Client client;
private WebTarget webTarget;
private JTextArea textArea;
public static void main(String[] args) {
new JaxRSTestApplication().start();
}
private class FetchDataAction extends AbstractAction{
private static final long serialVersionUID = 1L;
private FetchDataAction() {
putValue(Action.NAME, "fetch data");
}
@Override
public void actionPerformed(ActionEvent e) {
fetchData();
}
}
private void start() {
JFrame frame = new JFrame();
textArea = new JTextArea();
JButton reloadButton = new JButton(new FetchDataAction());
frame.add(textArea,BorderLayout.CENTER);
frame.add(reloadButton, BorderLayout.SOUTH);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setSize(new Dimension(400,400));
frame.setVisible(true);
this.client = ClientBuilder.newBuilder().build();
client.register(GZipEncoder.class);
client.register(EncodingFilter.class);
this.webTarget = client.target("http://localhost:8080/simple");
fetchData();
fetchData();
}
private void fetchData() {
// Get Method
Response response = this.webTarget.request().get();
// Extract the content
String result = response.readEntity(String.class);
textArea.setText(textArea.getText()+"\n"+"read:" + result);
response.close();
}
}
JNLP文件
<?xml version="1.0" encoding="utf-8"?>
<jnlp spec="1.0+" codebase="./">
<information>
<title>Jnlp Testing</title>
<vendor>de-jcup</vendor>
<homepage href="http://localhost:8080/" />
<description>Just a test application</description>
</information>
<security>
<all-permissions/>
</security>
<resources>
<j2se version="1.8+" />
<jar href="demo-1.0.0-fat.jar" />
</resources>
<application-desc main-class="com.example.demo.JaxRSTestApplication" />
</jnlp>
Spring REST 演示服务 + Gradle 设置
plugins {
id 'org.springframework.boot' version '2.6.0-SNAPSHOT'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id 'java-library'
id 'eclipse'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
dependencies {
api 'org.springframework.boot:spring-boot-starter-web'
}
package com.example.springrestdemo;
import java.util.concurrent.TimeUnit;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.CacheControl;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
public class SpringRestDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringRestDemoApplication.class, args);
}
@RestController
public class SimpleController {
private long secondWeWantTobeCached = 3600;
@GetMapping(value = "/simple", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<StringJsonObject> simpleResult() {
return ResponseEntity.ok().cacheControl(CacheControl.maxAge(secondWeWantTobeCached, TimeUnit.SECONDS).cachePublic().noTransform())
.body(new StringJsonObject("Timestamp:" + System.currentTimeMillis()));
}
public class StringJsonObject {
private String content;
public StringJsonObject(String content) {
this.content = content;
}
public String getContent() {
return content;
}
}
}
}
关于java - 运行形式 javaws - jakarta.ws.rs.client 在第一个之后不发送请求?客户端缓存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68873235/