I am trying to add log entries during start and as soon as request is responded (using ctx.addBodyEndHandler).
In below function foo what should be aaa?
private void foo(io.vertx.reactivex.ext.web.RoutingContext ctx) {
long start = System.currentTimeMillis();
String uuid = ctx.get("RequestIdentifier");
String clientAddress = ctx.request().remoteAddress().host();
LOG.info("Request ID: {}. Client IP: {}. Application type: {}. HTTP Method: {}. Body {}. Processing route: {}", uuid, clientAddress, this.getClientDescription(ctx.request()), ctx.request().method(), this.getRequestBody(ctx), ctx.request().uri());
ctx.addBodyEndHandler(ign -> {
LOG.info("Request ID: {} completed in {} ms. Response {}. Response code {}.", uuid, System.currentTimeMillis() - start, aaa, ctx.response().getStatusCode());
});
// more logic
}
You can't get the response body from the RoutingContext. Some responses may be very large so Vert.x doesn't store them.
If you are confident it will not harm your production system, you can store the body payload as context data before sending it:
routingContext.put("responseBody", content);
routingContext.response.end(content);
Then retrieve it in the bodyEnd handler:
String aaa = routingContext.get("responseBody");
Related
Normally definde a GRPC method as follows which has a request parameter HelloRequest:
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
But how to define a method without request parameter as following SayHello method:
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello () returns (HelloReply) {}
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
Google's Well-Known Types includes Empty
Given that you must have a message for requests and responses, I think it's a good idea to define them in your protos even if initially empty unless you're absolutely confident that they'll always be empty:
service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
message HelloRequest {}
message HelloReply {
string message = 1;
}
I'm trying to request a simple HTTP resource in Kotlin using Ktor's client library (1.4.1):
//
// DomainSpecificObjectFactory.kt
//
object DomainSpecificObjectFactory {
private val client = HttpClient {
UserAgent("some user agent string")
}
suspend fun fromUrl(url: String): DomainSpecificObject = coroutineScope {
val pageHtml = client.get<String>(url)
val document = Jsoup.parse(pageHtml)
val objProps = getDomainSpecificProperties(document)
DomainSpecificObject(objProps)
}
}
//
// SomeOtherFile.kt
//
val obj = DomainSpecificObjectFactory.fromUrl("http://example.com/bla")
However, I get this exception:
org.apache.http.ConnectionClosedException: Premature end of chunk coded message body: closing chunk expected
Should I be configuring the HTTP client any differently?
let's say i have a proto file like this. can I define service like this
rpc SayHello () returns (Response) {} //service has no input
rpc SayHello (Request1,Request2) returns (Response) {}//service has two inputs
//.proto file
syntax = "proto3";
service Greeter{
rpc SayHello (Request) returns (Response) {}
}
message Request{
string request = 1;
}
message Response{
string response = 1;
}
gRPC service methods have exactly one input message and exactly one output message. Typically, these messages are used as input and output to only one method. This is on purpose, as it allows easily adding new parameters later (to the messages) while maintaining backward compatibility.
If you don't want any input or output parameters, you can use the well-known proto google.protobuf.Empty. However, this is discouraged as it prevents you from adding parameters to the method in the future. Instead, you would be encouraged to follow the normal practice of having a message for the request, but simply with no contents:
service Greeter {
rpc SayHello (SayHelloRequest) returns (SayHelloResponse) {}
}
message SayHelloRequest {} // service has no input
Similarly, if you want two request parameters, just include both in the request message:
message SayHelloRequest { // service has two inputs
string request = 1;
string anotherRequestParam = 2;
}
I come from a C# background and would like to implement awaiting functionality in my Swift app. I've achieved my desired results but I had to use a semaphore which I'm not sure is good practice. I have a function with an alamo request that returns a JSON with a success value and as I understand it that request function is async with a completion handler. The handler fires once the request is complete. The problem is returning the success value from that operation. Here's a psuedo-code example of what I'm doing:
func AlamoTest() -> Bool{
var success = false
//Do some things...
//...
//Signal from async code
let semaphore = DispatchSemaphore(value: 0)
Alamofire.request("blah blah blah", method: .post, parameters: parameters, encoding: URLEncoding.default).responseJSON { response in {
success = response["success"]
if(success){
//Do some more things
}
semaphore.signal() //Signal async code is done
}
//Wait until async code done to get result
semaphore.wait(timeout: DispatchTime.distantFuture)
return success
}
Is there a "better" way of achieving my goal? I'm new to Swift and its async constructs.
Best solution I found is what I call "callback chaining". Example of my method looks like this:
func postJSON(json: NSDictionary, function: ServerFunction, completionHandler: ((_ jsonResponse: NSDictionary) -> Void)? = nil) {
//Create json payload from dictionary object
guard let payload = serializeJSON(json: json) else {
print("Error creating json from json parameter")
return
}
//Send request
Alamofire.request(urlTemplate(function.rawValue), method: .post, parameters: payload, encoding: URLEncoding.default).validate().responseJSON { response in
//Check response from server
switch response.result {
case .success(let data):
let jsonResponse = data as! NSDictionary
print("\(jsonResponse)")
//Execute callback post request handler
if completionHandler != nil {
completionHandler!(jsonResponse)
}
case .failure(let error):
print("Shit didn't work!\(error)")
}
}
}
The last parameter is a closure that executes once the orginal async operation is complete. You pass in the result to the closure and do what you want with it. In my case I wanted to disable the view while the async operations were rolling. You can enable the view in your closure argument since the result from the alamo async operation is called on the main thread. completionHandler defaults to nil if you don't need the result and stops the chaining.
You can use this framework for Swift coroutines - https://github.com/belozierov/SwiftCoroutine
func AlamoTest() throws -> Bool {
try Coroutine.await() { callback in
Alamofire.request("blah blah blah", method: .post, parameters: parameters, encoding: .default).responseJSON { response in
let success = response["success"]
callback(success)
}
}
}
and then call this method inside coroutine:
DispatchQueue.main.startCoroutine {
let result = try AlamoTest()
}
I'm using Jetty 9's implementation of HttpServletRequest#getPart(name), and it appears to eagerly processes the entire request (or at least the Part in question) before continuing, even though the resulting Part exposes a getInputStream() method.
Is there a way for getPart to return immediately, and leave request streaming to the resulting Part's InputStream?
For reference, here's the relevant snippet from my Servlet implementation:
override def doPost(req: HttpServletRequest, res: HttpServletResponse) {
println("ABOUT TO GET PART") // this happens immediately
val file = req.getPart("file")
println("GOT PART") // it takes a long time to get here if the upload is large
It's wicked tedious, but this can be done using MultipartStream from commons-fileupload:
try {
MultipartStream multipartStream = new MultipartStream(input, boundary);
boolean nextPart = multipartStream.skipPreamble();
OutputStream output;
while(nextPart) {
String header = multipartStream.readHeaders();
// process headers
// create some output stream
multipartStream.readBodyData(output);
nextPart = multipartStream.readBoundary();
}
} catch(MultipartStream.MalformedStreamException e) {
// the stream failed to follow required syntax
} catch(IOException e) {
// a read or write error occurred
}
This requires the use of the InputStream from HttpServletRequest#getInputStream(), and the boundary delimiter encoded in the HTTP request's content type:
Content-Type: multipart/form-data; boundary=------------------------bd019839518ca918