2016-03-30 18 views
2

Sunucu Gönderilen Olaylar için yeniyim ama İlkbahar'a değil. SSEEmitter'i başlatan ve bunu her 4 saniyeden sonra UI'ye iletiyi ileten başka bir ileticiye geçiren UI üzerindeki bir düğmeden tetiklenen bir denetleyici yaptık. Şimdiye kadar her biri 4 saniyeliğine 4 kez uyuyan, ancak 6 ya da 7. döngüde yinelenen 10'luk bir döngü çalıştırıyorum, istisna alıyorum "Konuda özel durum" Thread-4 "java.lang.IllegalStateException: ResponseBodyEmitter zaten tamamlandı" Bu nedenle, olay kaynağı tekrar bağlantıyı yeniden kurar, yani kesinlikle istemediğim kontrolör yöntemini tekrar çağırır.Spring SSEEmitter Tamamlandı Orta yol

Ben basit bir şey denemek için buradayım .. Kullanıcı butonuna tıklayarak abone olursunuz .. Sunucu tarayıcıya ne zaman olursa olsun 10 veya 20 yanıtı gönderin. Ve düşündüğüm kadarıyla bu, SSE'nin yarattığı şey. .:

@RequestMapping("/subscribe") 
public SseEmitter subscribe() { 
    SseEmitter sseEmitter = new SseEmitter(); 
    try { 
     sseEmitter.send("Dapinder"); 
    } catch (IOException e) { 
     // TODO Auto-generated catch block 
     e.printStackTrace(); 
    } 
    Runnable r = new AnotherThread(sseEmitter); 
    new Thread(r).start(); 
    return sseEmitter; 
} 

public class AnotherThread altında

Kod uygulayan Runnable {

private SseEmitter sseEmitter; 

public AnotherThread(SseEmitter sseEmitter) { 
    super(); 
    this.sseEmitter = sseEmitter; 
} 

@Override 
public void run() { 
    SseEventBuilder builder = SseEmitter.event(); 
    builder.name("dapEvent"); 
    for (int i = 0; i < 10; i++) { 
     builder.data("This is the data: " + i +" time."); 
     try { 
      //sseEmitter.send(builder); 
      sseEmitter.send("Data: "+i); 
      //sseEmitters.get(1L).send("Hello"); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     try { 
      Thread.sleep(4000); 
     } catch (InterruptedException e) { 
      e.printStackTrace(); 
     } 
    } 
    sseEmitter.complete(); 
} 

public SseEmitter getSseEmitter() { 
    return sseEmitter; 
} 

public void setSseEmitter(SseEmitter sseEmitter) { 
    this.sseEmitter = sseEmitter; 
} 

}

function start() { 
    var eventSource = new EventSource("http://localhost:8080/HTML5SSE/springSSE/subscribe"); // /springSSE/connect 
     eventSource.onmessage = function(event) { 
     document.getElementById('foo').innerHTML = event.data; 
    }; 

} 


<button onclick="start()">Subscribe</button> 
+0

Bu konuya bir bakın: http://stackoverflow.com/questions/29880336/spring-sseemitter-causes-cannot-forward-after-response-has-been-committed-except. Aynı konuya benziyor. – ctranxuan

+0

Aynı problemim var. Başka bir iş parçacığında SseEmitter üzerinde göndermek için hazır olduğumda, zaman aşımı veya bir yerde tamamladı ve bir IllegalStateException atar. İyi bir çözüm buldunuz mu? –

cevap

2

Kişisel oluşturucu kullanılmıyor; Bir oluşturucu oluşturup yapılandırırsınız, ancak doğrudan 'sseEmitter.send' ile düz bir mesaj gönderirsiniz. Bunu deneyin:

sseEmitter.send(SseEmitter.event().name("dapEvent").data("This " + i +" time."); 

Bir şey daha: Neden abone yönteminde zaten gönderme yöntemini çağırıyorsunuz? Bu noktada, SseEmitter iade edilmedi. Bu mesaj müşteriye geliyor mu?

Burada, JavaScript perspektifinden (Spring değil) SSE'yi açıklayan bir excellent article1 var. Burada, akışın yakınından arayarak olay akışını istemciden iptal edebildiğinizi göreceksiniz. Olay dinleyicisi ile birleştirin ve size ne gerek olmalıdır:

var source = new EventSource('...'); 
source.addEventListener('error', function(e) { 
    if (e.currentTarget.readyState == EventSource.CLOSED) { 
    // Connection was closed. 
    } else { 
    // Close it yourself 
    source.close(); 
    } 
}); 
source.addEventListener('message', function(e) { 
    console.log(e.data); 
}); 

Not: makale e.readyState diyor, ancak bunun yanlış olduğunu düşünüyorum. Alınan nesne e, bir Event'dur. EventSource nesnesini şu şekilde elde etmeniz gerekir: e.currentTarget.

1

Bir Uzun zaman aşımı argüman alır ikinci yapıcısı SseEmitter kullanmak gerekir. aşağıdaki kodu bakın -

@RequestMapping("/subscribe") 
public SseEmitter subscribe() { 
    SseEmitter sseEmitter = new SseEmitter(Long.MAX_VALUE) // for maximum timeout 

Aşağıda bu yapıcı Java-dokümanın kopyasıdır -

/** 
* Create a SseEmitter with a custom timeout value. 
* <p>By default not set in which case the default configured in the MVC 
* Java Config or the MVC namespace is used, or if that's not set, then the 
* timeout depends on the default of the underlying server. 
* @param timeout timeout value in milliseconds 
* @since 4.2.2 
*/ 

Tomcat içinde SSE bağlantısının varsayılan zaman aşımı 40 saniyedir düşünüyorum. Yine de emin değilim.