有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Spring RestTemplate调用时java读取超时

我有一个API,它返回一个json,它的类型是GET-method。因为它是GET,所以当我在浏览器中打开URL时,它可以正常工作并呈现json,但是,在使用RestTemplate检索json时,它失败了

请您提供一种方式来阅读下面的API

API URL:https://www.nseindia.com/api/option-chain-indices?symbol=NIFTY

Spring引导Rest模板调用:

final String uri = "https://www.nseindia.com/api/option-chain-indices?symbol=NIFTY";
RestTemplate restTemplate = new RestTemplate();
Map result = restTemplate.getForObject(uri, Map.class);

错误:

java.net.SocketTimeoutException: Read timed out
    at java.base/java.net.SocketInputStream.socketRead0(Native Method) ~[na:na]
    at java.base/java.net.SocketInputStream.socketRead(SocketInputStream.java:115) ~[na:na]
    at java.base/java.net.SocketInputStream.read(SocketInputStream.java:168) ~[na:na]
    at java.base/java.net.SocketInputStream.read(SocketInputStream.java:140) ~[na:na]
    at java.base/sun.security.ssl.SSLSocketInputRecord.read(SSLSocketInputRecord.java:448) ~[na:na]
    at java.base/sun.security.ssl.SSLSocketInputRecord.bytesInCompletePacket(SSLSocketInputRecord.java:68) ~[na:na]
    at java.base/sun.security.ssl.SSLSocketImpl.readApplicationRecord(SSLSocketImpl.java:1104) ~[na:na]
    at java.base/sun.security.ssl.SSLSocketImpl$AppInputStream.read(SSLSocketImpl.java:823) ~[na:na]
    at java.base/java.io.BufferedInputStream.fill(BufferedInputStream.java:252) ~[na:na]
    at java.base/java.io.BufferedInputStream.read1(BufferedInputStream.java:292) ~[na:na]
    at java.base/java.io.BufferedInputStream.read(BufferedInputStream.java:351) ~[na:na]
    at java.base/sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:746) ~[na:na]
    at java.base/sun.net.www.http.HttpClient.parseHTTP(HttpClient.java:689) ~[na:na]

共 (3) 个答案

  1. # 1 楼答案

    您可以使用webflux的WebClient:

    -添加依赖项

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-webflux</artifactId>
    </dependency>
    

    -创建POJO

    @Data
    public class Root {
        private Records records;
        private Filtered filtered;
    
        @Data
        public static class PE {
            private int strikePrice;
            private String expiryDate;
            private String underlying;
            private String identifier;
            private int openInterest;
            private int changeinOpenInterest;
            private double pchangeinOpenInterest;
            private int totalTradedVolume;
            private double impliedVolatility;
            private double lastPrice;
            private double change;
            private double pChange;
            private int totalBuyQuantity;
            private int totalSellQuantity;
            private int bidQty;
            private double bidprice;
            private int askQty;
            private double askPrice;
            private double underlyingValue;
        }
    
        @Data
        public static class CE {
            private int strikePrice;
            private String expiryDate;
            private String underlying;
            private String identifier;
            private int openInterest;
            private int changeinOpenInterest;
            private int pchangeinOpenInterest;
            private int totalTradedVolume;
            private int impliedVolatility;
            private int lastPrice;
            private double change;
            private double pChange;
            private int totalBuyQuantity;
            private int totalSellQuantity;
            private int bidQty;
            private double bidprice;
            private int askQty;
            private double askPrice;
            private double underlyingValue;
        }
    
        @Data
        public static class Datum {
            private int strikePrice;
            private String expiryDate;
            private PE PE;
            private CE CE;
        }
    
        @Data
        public static class Records {
            private List<String> expiryDates;
            private List<Datum> data;
            private String timestamp;
            private double underlyingValue;
            private List<Integer> strikePrices;
        }
    
        @Data
        public static class Filtered {
            //TODO
        }
    }
    

    -让WebClient打电话

    @SpringBootApplication
    public class MultipleConfigurationPropertiesApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(MultipleConfigurationPropertiesApplication.class, args);
        }
    
        @Bean
        CommandLineRunner commandLineRunner() {
            return args -> {
                WebClient client = WebClient.builder()
                        .baseUrl("https://www.nseindia.com")
                        .exchangeStrategies(ExchangeStrategies.builder()
                                .codecs(configurer -> configurer
                                        .defaultCodecs()
                                        .maxInMemorySize(16 * 1024 * 1024))
                                .build())
                        .build();
    
                Mono<Root> result = client.get()
                        .uri("/api/option-chain-indices?symbol=NIFTY").accept(MediaType.APPLICATION_JSON)
                        .retrieve()
                        .bodyToMono(Root.class);
    
                System.out.println(result.block());
            };
        }
    }
    

    由于请求结果巨大,您必须调整缓冲区大小

    也可以考虑使用非阻塞/流解决方案来处理这个问题。

  2. # 2 楼答案

    当连续数据包之间达到最大不活动时间时,就会出现这样的读取超时。初始化RestTemplate时,必须为其提供一个读取超时配置的ClientHttpRequestFactoryHere就是这样做的一个例子

    您可能还想考虑将REST模板制作成bean,如果您必须多做这些长时间运行的请求。这样,您就不必每次都重新配置

  3. # 3 楼答案

    不久前,我在浏览器中测试了API GET请求,结果是高度嵌套的。您试图将结果检索到Map对象中,但没有指定KeyValue的类型,后者可能是MapList本身

    首先,确定是否可以将原始JSON结果检索到String

    ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
    

    如果这样做有效,那么您将知道GET请求通过RestTemplate工作。如果没有,您可以对默认timeout settings进行故障排除,并根据您在浏览器中观察网络响应的时间进行调整

    假设您可以将原始JSON结果检索到String,那么下一步将是分析返回的JSON数据的“形状”。如果希望将JSON结果转换为POJO,则必须创建一个与JSON数据的“形状”匹配的类(或一组类)

    records:
        
      expiryDates   […]
      data  […]
      timestamp "31-Aug-2020 15:30:00"
      underlyingValue   11387.5
      strikePrices  […]
    
    filtered:   
      data  […]
      CE    
        totOI   367314
        totVol  4988131
      PE    
        totOI   261696
        totVol  5501580