簡體   English   中英

Spring ResponseBodyEmitter沒有在響應中設置Content-Type標頭

[英]Spring ResponseBodyEmitter doesn't set Content-Type header in a response

我正在為請求處理程序編寫一種包裝程序,以使它們流式傳輸HTTP響應。 我現在所擁有的是

處理程序響應包裝器:

 @Component
public class ResponseBodyEmitterProcessor {

    public ResponseBodyEmitter process(Supplier<?> supplier) {
        ResponseBodyEmitter emitter = new ResponseBodyEmitter();
        Executors.newSingleThreadExecutor()
                .execute(() -> {
                    CompletableFuture<?> future = CompletableFuture.supplyAsync(supplier)
                            .thenAccept(result -> {
                                try {
                                    emitter.send(result, MediaType.APPLICATION_JSON_UTF8);
                                    emitter.complete();
                                } catch (IOException e) {
                                    emitter.completeWithError(e);
                                }
                            });
                    while (!future.isDone()) {
                        try {
                            emitter.send("", MediaType.APPLICATION_JSON_UTF8);
                            Thread.sleep(500);
                        } catch (IOException | InterruptedException e) {
                            emitter.completeWithError(e);
                        }
                    }
                });

        return emitter;
    }
}

控制器:

@RestController
@RequestMapping("/something")
public class MyController extends AbstractController {

    @GetMapping(value = "/anything")
public ResponseEntity<ResponseBodyEmitter> getAnything() {
    return ResponseEntity.ok()
            .contentType(MediaType.APPLICATION_JSON_UTF8)
            .body(process(() -> {
                //long operation
            }));
}

我正在做的就是每半秒發送一次空字符串以保持請求有效。 某些工具需要不通過超時將其關閉。 這里的問題是我在響應中看不到任何Content-Type標頭。 根本沒有任何東西,盡管我從控制器方法中返回ResponseEntity,正如在該線程中所說的那樣:

https://github.com/spring-projects/spring-framework/issues/18518

看起來只有TEXT_HTML媒體類型可以接受流式傳輸。 根本沒有流json的方法嗎? 我什至使用objectMapper手動將dtos映射到json字符串,但是仍然沒有運氣。 嘗試過APPLICATION_JSON和APPLICATION_STREAM_JSON-不起作用。 在不同的瀏覽器中嘗試過-結果相同。

我還手動在控制器中為ResponseEntity設置Content-Type標頭。 現在響應中有標題,但是我不確定數據是否真的在流化。 在Chrome瀏覽器中,我只能看到操作的結果,而看不到我正在發送的中間字符(將它們更改為“ a”進行測試)。

我檢查了兩個選項的請求處理時間:

沒有發射器(只是通常的控制器處理程序) 沒有發射器

帶發射器 帶發射器

據我了解,等待狀態的意思是:“等待第一個字節出現”。 似乎與發射器一樣,第一個字節出現得更早-這看起來像我需要的。 我可以認為這是我的解決方案有效的證明嗎?

也許在春季還有另一種方法嗎? 我需要的只是通過向瀏覽器發送一些無用的數據來通知瀏覽器該請求仍在處理中,直到完成實際操作為止-然后返回結果。

任何幫助將非常感激。

查看ResponseBodyEmitter#send的來源,似乎應該已經在AbstractHttpMessageConverter#addDefaultHeaders方法中設置了指定的MediaTypeAbstractHttpMessageConverter#addDefaultHeaders是沒有其他contentType頭。

protected void addDefaultHeaders(HttpHeaders headers, T t, MediaType contentType) throws IOException{
    if (headers.getContentType() == null) {
        MediaType contentTypeToUse = contentType;
        // ...
        if (contentTypeToUse != null) {
            headers.setContentType(contentTypeToUse);
        }
    }
    // ...
}

我建議在此處設置一個斷點,看看為什么不應用標題。 也許@RestController設置了默認頭。

解決方法是,您可以嘗試通過MVC控制器中的注釋設置contentType標頭。

例如

@RequestMapping(value = "/something", produces = MediaType.APPLICATION_JSON_UTF8)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM