java - 运行形式 javaws - jakarta.ws.rs.client 在第一个之后不发送请求?客户端缓存?

标签 java rest caching request java-web-start

我有一个 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 启动

Java web start 客户端的输出:
Result

总结

我使用了来自 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/

相关文章:

java - 组织.json.JSONException : Missing value at character 1

java - 我的 JVM 内存泄漏在哪里?垃圾收集器工作正常吗?

c# - 底层连接已关闭 : An unexpected error occurred on a receive

ajax - 代理外部 REST Api 的正确方法?

go - Race(?) with Mutex - map 中的数据损坏

php - 如何在 CodeIgniter 中清除页面缓存

java - JSF2 和 RichFaces 的分层数据表

java - 在j2EE中加载外部文件的最佳方式?

python - 如何为django预缓存模板

java - 如何将 2 byte[] 从 JNI 传递给 Java