As described in the title I would like to send messages to a Websocket using RabbitMQ. Using AngularJS frontend I want to read the RabbitMQ messages from the Websocket and print them to the console.
In principle my code seems the work, though I can't figure out how to get the actual (string) content of my messages?
Backend:
To create the Websocket and do the routing i am using Spring Boot and Apache Camel: http://camel.apache.org/spring-boot.html.
Routing with Camel is easy and my complete Java Code looks like this:
#Component
public final class CamelRoute extends RouteBuilder {
#Override
public final void configure() throws Exception {
from("rabbitmq:localhost/myExchange")
.to("websocket://myEndpoint?sendToAll=true");
}
}
Running the SpringBoot application works without errors and the logs look good:
Route: route1 started and consuming from: rabbitmq://localhost/myExchange
RabbitMQ:
RabbitMQ runs on my localhost. When I go to http://localhost:15672/ I can see that SpringBoot created the myExchange and I can send messages to it using Publish Message in the UI.
For instance I specify "HelloWorld!" as Payload (without any headers etc.) and click on send.
Frontend:
To read messages from the websocket I basically do the following in my AngularJS controller:
var socket = {
start: function () {
var location = "ws://localhost:9292/myEndpoint";
this._ws = new WebSocket(location);
this._ws.onmessage = this._onmessage;
this._ws.onclose = this._onclose;
},
_onmessage: function (m) {
//Log received RabbitMQ messages from the Websocket
console.log(m);
},
_onclose: function (m) {
if (this._ws) {
this._ws.close();
}
}
};
Receiving the messages seems to work in principle.
When I go to my webpage (localhost:8080/) and open the console in Chrome, it prints a "MessageEvent" object with many properties.
None of these properties though seem tocontain the actual message string, i.e.: "HelloWorld!"?
Update:
Instead of using RabbitMQ to deliver messages, I tried doing the same with Apache Kafka instead, and it worked. Here is what I did:
To test I simply setup a Topic called "test" on a local Kafka Broker using a docker-image.
My route config now looks like this:
from("kafka:localhost:9092?topic=test&groupId=camelgroupid&autoOffsetReset=earliest&consumersCount=1")
.to("websocket://dashboard?sendToAll=true");
To send messages I use the official kafka clients library.
Using the same JS code as posted above, I can now see the messages in the MessageObject.data.
I still wonder why the same approach doesn't work with RabbitMQ? Anyone has an idea?
Finally solved my problem.
The problem was at the client-side. RabbitMQ sends messages via byte[]. The byte[] needs to be decoded correctly when reading the the message from the Websocket.
Here is my updated and working client code:
var socket = {
start: function () {
var location = "ws://localhost:9292/myEndpoint";
this._ws = new WebSocket(location);
// RabbitMQ transmits a byte[], therefore we need to change the binary type:
this._ws.binaryType = 'arraybuffer';
this._ws.onmessage = this._onmessage;
this._ws.onclose = this._onclose;
},
_onmessage: function (m) {
// Decode the byte[]:
var messageString = new TextDecoder('UTF-8').decode(m.data);
console.log(messageString);
},
_onclose: function (m) {
if (this._ws) {
this._ws.close();
}
}
};
Related
We are using react js with springboot. We have written the service and check from postman form-data. It's working but when we use react js it's not working. Rest End point hit but not load the payload data to the service.
for React we are using const formData = new FormData() and append all the required input.
React Code
const formData = new FormData();
formData.append("event", this.state.status);
formData.append("startDate", this.state.startDateTxt);
formData.append("sourceSystem", this.state.sourceSystem);
formData.append("endDate", this.state.endDateTxt);
formData.append("minPrice", this.state.minPrice);
formData.append("maxPrice", this.state.maxPrice);
httpRequest.open("POST", "http://localhost:8080/sa/searchData", true);
httpRequest.setRequestHeader("Content-Type","application/form-data");
httpRequest.onreadystatechange = () => {
console.log("httpRequest.readyState",
httpRequest.readyState);
if (httpRequest.readyState === XMLHttpRequest.DONE
&& httpRequest.status === 200) {
console.log("httpRequest.responseText ", httpRequest.responseText);
updateData(JSON.parse(httpRequest.responseText));
}
};
httpRequest.send(formData);
spring boot
#PostMapping(value = "/sa/searchData")
public List<DataResponse> searchData(SearchCriteria searchCriteria) {
return saService.searchData(searchCriteria);
}
The error code '408' suggests that the problem is in the react code that is sending form data.
The server sends '408' error when the client has sent an incomplete request to it.
The problem can be traced to the block of statements beginning from
'httpRequest.open("POST", "localhost:8080/sa/searchData", true); ...
This code block is opening the connection with the server, but never finishing sending the request.
This is causing the server to time out waiting for the complete request from client, and eventually send 408 error.
How to fix the problem?
Add a .send() method after .open() to complete the sending of the HTTP request.
An example of working code snippet:
httpRequest.open('POST', "localhost:8080/sa/searchData", true)
// add headers and other parameters
// Send the request
httpRequest.send()
More information:
https://malcoded.com/posts/react-http-requests-axios/
First off, I just started trying to add SignalR 2 to my existing Angular SPA project.
I have a main controller which starts the hub right away that is feeding some messages to the client. Inside, I have several sub pages and each could subscribe to a different hub for services. The problems is that the client doesn't receive message because it is hooked up after the hub is already started in the main controller.
As a test, if I comment out the hub start in the main controller, the one in the sub controller works fine.
From what I read, it is by design that you have to hook up all client calls before starting the hub. I don't understand...if it is a service, I should be able to subscribe or unsubscribe anytime after the hub is started. Why not? How to workaround?
Because no response in the 12 hours (which is quite unusual in so), I had to dig around myself. I think, I was misled by the answers from SO on related questions that you have to subscribe all client call before starting the connection, as mentioned e.g. here. I found in Hubs API Guide, one section says
Define method on client (without the generated proxy, or when adding
after calling the start method)
So, it is possible to add client method after connection is started. The trick is to use so-called "without the generated proxy". That limitation is for "with generated proxy".
The following is my working example taken from SignalR get started tutorial.
This is the main controller using "with generated proxy":
$.connection.statusHub.client.updateStatus = function (status) {
$scope.status = status;
$scope.$apply();
}
$.connection.hub.start();
This is in a subcontroller using "without generated proxy":
var connection = $.hubConnection();
var proxy = connection.createHubProxy('stockTickerHub');
proxy.on('updateStockPrice', function (stock) {
var st = $scope.stocks.firstOfKey(stock.symbol, 'symbol');
st.lastPrice = stock.lastPrice;
$scope.$apply();
});
var hub = $.connection.stockTickerHub;
connection.start().done(function () {
hub.server.getAllStocks().done(function (stocks) {
$scope.stocks = stocks;
});
});
Note that it doesn't work if I use "with generated proxy" in the subcontroller like this:
var hub = $.connection.stockTickerHub;
hub.client.updateStockPrice = function (stock) {
var st = $scope.stocks.firstOfKey(stock.symbol, 'symbol');
st.lastPrice = stock.lastPrice;
$scope.$apply();
};
$.connection.hub.start().done(function () {
hub.server.getAllStocks().done(function (stocks) {
$scope.stocks = stocks;
});
});
To prove the limitation of "with generated proxy" mode, this code works if I comment out the one in the main controller.
By the way, I was so confused by the term with or without generated proxy in the Guide, and in both cases, it is still called xxxProxy. Can't they find a better name? Or somebody has an explanation?
I'm creating a SAGA in NServiceBus. This saga is handling some string which has to be transformed then validated and finally imported. These three actions are separate services. I want the actions as separate handlers in NServiceBus. I'm using the Request/Reply functionality in NServiceBus. Like this:
Bus.Send<TransformRequest>("Backend", m =>
{
m.string = string;
m.MessageId = messageId;
})
.Register(i =>
{
Console.WriteLine("transform finished")
});
The transformationHandler is as follows.
public void Handle(TransformRequest message)
{
var transformationResult = _transformationService.Transform(message.string);
var response = new TransformResponse()
{
string= transformationResult,
messageId = message.messageId,
};
Bus.Reply(response);
}
My question is as follows. When a request is sent to the transformationHandler. A message is sent to the messagequeue. Then hypothetical, the server crashes. The server reboots, the server picks up the TransformationRequest, does it work and wants to do a reply to the Saga, but how? The saga is not alive anymore and can't handle the .Register. How do I handle this problem?
Thank you.
NServiceBus will find the saga instance using a header in the response message automatically for you.
As Sean mentions you need to skip .Register and add a handler for transform result in your saga. The reason is that callbacks using .Register is stored in memory and therefor won't survive a restart
I have an AngularJS application that I intend to have receive communications via SignalR from the server, most notably when data changes and I want the client to refresh itself.
The following is my hub logic:
[HubName("update")]
public class SignalRHub : Hub
{
public static void SendDataChangedMessage(string changeType)
{
var context = GlobalHost.ConnectionManager.GetHubContext<SignalRHub>();
context.Clients.All.ReceiveDataChangedMessage(changeType);
}
}
I use the following within my API after the data operation has successfully occurred to send the message to the clients:
SignalRHub.SendDataChangedMessage("newdata");
Within my AngularJS application, I create a service for SignalR with the following javascript that's referenced in the HTML page:
angular.module('MyApp').value('signalr', $.connection.update);
Within the root for the AngularJS module, I set this up with the following so that it starts and I can see the debug output:
$(function () {
$.connection.hub.logging = true;
$.connection.hub.start();
});
$.connection.hub.error(function(err) {
console.log('An error occurred: ' + err);
});
Then I've got my controller. It's got all sorts of wonderful things in it, but I'll show the basics as relate to this issue:
angular.module('MyApp').controller('MyController', function($scope, signalr) {
signalr.client.ReceiveDataChangedMessage = function dataReceived(changeType) {
console.log('DataChangedUpdate: ' + changeType);
};
});
Unfortunately, when I set a breakpoint in the javascript, this never executes though the rest of the program works fine (including performing the operation in the API).
Some additional (hopefully) helpful information:
If I set a breakpoint in the SignalRHub class, the method is successfully called as expected and throws no exceptions.
If I look at Fiddler, I can see the polling operations but never see any sign of the call being sent to the client.
The Chrome console shows that the AngularJS client negotiates the websocket endpoint, it opens it, initiates the start request, transitions to the connected state, and monitors the keep alive with a warning and connection lost timeout. There's no indication that the client ever disconnects from the server.
I reference the proxy script available at http://localhost:port/signalr/hubs in my HTML file so I disregard the first error I receive stating that no hubs have been subscribed to. Partly because the very next message in the console is the negotiation with the server and if I later use '$.connection.hub' in the console, I'll see the populated object.
I appreciate any help you can provide. Thanks!
It's not easy to reproduce it here, but it's likely that the controller function is invoked after the start of the connection. You can verify with a couple of breakpoints on the first line of the controller and on the start call. If I'm right, that's why you are not called back, because the callback on the client member must be defined before starting the connection. Try restructuring your code a bit in order to ensure the right order.
I'm developing a recorder in silverlight and I need to upload data from stream to the web server after recording process is completed.
On server side I'm using ASP.NET MVC 3, and I have created a Controller with method FileUpload.
public class FileUploaderController : Controller
{
[HttpPost]
public ActionResult FileUpload(string fileName)
{
....
}
}
In silverlight applet, the upload is made by parts, about 20000 bytes at time. Servers web config is configured to accept larger amount of data.
Server returns an exception "The remote server returned an error: NotFound.".
In this case the request have not reached the action and I can't understand why.
Example of code that is used to start upload:
UriBuilder httpHandlerUrlBuilder = new UriBuilder("http://localhost:37386/FileUploader/FileUpload/?fileName=" + Guid.NewGuid() + ".wav");
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(httpHandlerUrlBuilder.Uri);
webRequest.Method = "POST";
webRequest.ContentType = "multipart/form-data"; // This solved my problem
webRequest.BeginGetRequestStream(new AsyncCallback(WriteToStreamCallback), webRequest);
EDIT
My route configuration is by default:
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
When the small amount of data is sent, everything goes well and server receives the requested data. But when data to be send is larger I'm just getting NotFound response. This doesn't make any sense to me, what I'm doing is:
HttpWebRequest to send 20000 bytes
close request stream (obtained from request.EndGetRequestStream)
wait for server response (from webRequest.EndGetResponse) This is where error occurs.
In my case, I never send more than 20000 bytes, which is strange this to work sometimes and others not.
I don't know a better way to explain this problem. If you need I can provide more code and more information.
Any help is very much appreciated.
With filddler I was able to get more detailed information regarding to the error. It was "upload file potentially dangerous Request.Form value was detected from the client...".
To solve this I've specified content-type of the webRequest to "multipart/form-data"