I used QNetworkAccessManager to handle send a http request:
void f()
{
QNetworkRequest request( QUrl( address ) );
QNetworkAccessManager mng;
mng.get(request);
//QEventLoop().exec();
}
void main()
{
...
f();
...
}
If without line QEventLoop().exec();, the app will not send request. But if with line QEventLoop().exec();, it will. I don't understan why?
Can you clear me?
Thank you very much!
(P/s: I have seen this link: Sending an HTTP request using QNetworkAccessManager)
void f()
{
static QNetworkRequest request( QUrl( address ) );
static QNetworkAccessManager mng;
mng.get(request);
}
void main()
{
...
f();
...
}
I think this is because QNetworkAccessManager is asynchronous and need the time to send the request. But require, url, query, ... is destroyed when out of scope.
-> we need in scope when QNetworkAccessManager do send request (use QEventLoop().exec(); ) or let require, url, query, ... is persistent (declare it with static).
Related
For any 4xx or 5xx response given out by my micronaut server, I'd like to log the response status code and endpoint it targeted. It looks like a filter would be a good place for this, but I can't seem to figure out how to plug into the onError handling
for instance, this filter
#Filter("/**")
class RequestLoggerFilter: OncePerRequestHttpServerFilter() {
companion object {
private val log = LogManager.getLogger(RequestLoggerFilter::class.java)
}
override fun doFilterOnce(request: HttpRequest<*>, chain: ServerFilterChain): Publisher<MutableHttpResponse<*>>? {
return Publishers.then(chain.proceed(request), ResponseLogger(request))
}
class ResponseLogger(private val request: HttpRequest<*>): Consumer<MutableHttpResponse<*>> {
override fun accept(response: MutableHttpResponse<*>) {
log.info("Status: ${response.status.code} Endpoint: ${request.path}")
}
}
}
only logs on a successful response and not on 4xx or 5xx responses.
How would i get this to hook into the onError handling?
You could do the following. Create your own ApplicationException ( extends RuntimeException), there you could handle your application errors and in particular how they result into http error codes. You exception could hold the status code as well.
Example:
class BadRequestException extends ApplicationException {
public HttpStatus getStatus() {
return HttpStatus.BAD_REQUEST;
}
}
You could have multiple of this ExceptionHandler for different purposes.
#Slf4j
#Produces
#Singleton
#Requires(classes = {ApplicationException.class, ExceptionHandler.class})
public class ApplicationExceptionHandler implements ExceptionHandler<ApplicationException, HttpResponse> {
#Override
public HttpResponse handle(final HttpRequest request, final ApplicationException exception) {
log.error("Application exception message={}, cause={}", exception.getMessage(), exception.getCause());
final String message = exception.getMessage();
final String code = exception.getClass().getSimpleName();
final ErrorCode error = new ErrorCode(message, code);
log.info("Status: ${exception.getStatus())} Endpoint: ${request.path}")
return HttpResponse.status(exception.getStatus()).body(error);
}
}
If you are trying to handle Micronaut native exceptions like 400 (Bad Request) produced by ConstraintExceptionHandler you will need to Replace the beans to do that.
I've posted example here how to handle ConstraintExceptionHandler.
If you want to only handle responses itself you could use this mapping each response code (example on #Controller so not sure if it works elsewhere even with global flag:
#Error(status = HttpStatus.NOT_FOUND, global = true)
public HttpResponse notFound(HttpRequest request) {
<...>
}
Example from Micronaut documentation.
Below code I used for adding custom cors headers in the error responses, in doOnError you can log errors
#Filter("/**")
public class ResponseCORSAdder implements HttpServerFilter {
#Override
public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request, ServerFilterChain chain) {
return this.trace(request)
.switchMap(aBoolean -> chain.proceed(request))
.doOnError(error -> {
if (error instanceof MutableHttpResponse<?>) {
MutableHttpResponse<?> res = (MutableHttpResponse<?>) error;
addCorsHeaders(res);
}
})
.doOnNext(res -> addCorsHeaders(res));
}
private MutableHttpResponse<?> addCorsHeaders(MutableHttpResponse<?> res) {
return res
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Methods", "OPTIONS,POST,GET")
.header("Access-Control-Allow-Credentials", "true");
}
private Flowable<Boolean> trace(HttpRequest<?> request) {
return Flowable.fromCallable(() -> {
// trace logic here, potentially performing I/O
return true;
}).subscribeOn(Schedulers.io());
}
}
How to use Volley to fetch recipes from spoonacular API for an android application. I am new to APIs and would like some help in fetching recipes from the spoonacular api for a list of ingredients specified in an android app.
Step 1
dependencies {
...
implementation 'com.android.volley:volley:1.0.0'
}
Step 2
In AndroidManifest file add permission
<uses-permission android:name="android.permission.INTERNET"/>
Step 3 Add following in MyApplication class
private RequestQueue requestQueue;
public RequestQueue getRequestQueue() {
if (requestQueue == null)
requestQueue = Volley.newRequestQueue(getApplicationContext());
return requestQueue;
}
public void addToRequestQueue(Request request, String tag) {
request.setTag(tag);
getRequestQueue().add(request);
}
public void cancelAllRequests(String tag) {
getRequestQueue().cancelAll(tag);
}
Step 4 Final Step
//URL of the request we are sending
String url = "https://api.spoonacular.com/food/products/22347";
/*
JsonObjectRequest takes in five paramaters
Request Type - This specifies the type of the request eg: GET,
URL - This String param specifies the Request URL
JSONObject - This parameter takes in the POST parameters.null in case of
GET request
Listener -This parameter takes in a implementation of Response.Listener()
interface which is invoked if the request is successful
Listener -This parameter takes in a implemention of Error.Listener()
interface which is invoked if any error is encountered while processing
the request
*/
JsonObjectRequest jsonObjReq = new JsonObjectRequest(Request.Method.GET,
url, null,
new Response.Listener() {
#Override
public void onResponse(JSONObject response) {
//Success Callback
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
//Failure Callback
}
});
// Adding the request to the queue along with a unique string tag
MyApplication.getInstance().addToRequestQueue(jsonObjectReq, "getRequest");
Something like that. Let's try. Thanks
I have a sample where I make a client request to debug token request to the FB api, and return the result to the client.
Depending on whether the access token is valid, an appropriate header should be returned:
#Override
public ServerServiceCall<LoginUser, Pair<ResponseHeader, String>> login() {
return this::loginUser;
}
public CompletionStage<Pair<ResponseHeader, String>> loginUser(LoginUser user) {
ObjectMapper jsonMapper = new ObjectMapper();
String responseString = null;
DebugTokenResponse.DebugTokenResponseData response = null;
ResponseHeader responseHeader = null;
try {
response = fbClient.verifyFacebookToken(user.getFbAccessToken(), config.underlying().getString("facebook.app_token"));
responseString = jsonMapper.writeValueAsString(response);
} catch (ExecutionException | InterruptedException | JsonProcessingException e) {
LOG.error(e.getMessage());
}
if (response != null) {
if (!response.isValid()) {
responseHeader = ResponseHeader.NO_CONTENT.withStatus(401);
} else {
responseHeader = ResponseHeader.OK.withStatus(200);
}
}
return completedFuture(Pair.create(responseHeader, responseString));
}
However, the result I get is:
This isn't really what I expected. What I expect to receive is an error http status code of 401, and the json string as defined in the code.
Not sure why I would need header info in the response body.
There is also a strange error that occurs when I want to return a HeaderServiceCall:
I'm not sure if this is a bug, also I am a bit unclear about the difference between a ServerServiceCall and HeaderServiceCall.
Could someone help?
The types for HeaderServiceCall are defined this way:
interface HeaderServiceCall<Request,Response>
and
CompletionStage<Pair<ResponseHeader,Response>> invokeWithHeaders(RequestHeader requestHeader,
Request request)
What this means is that when you define a response type, the return value should be a CompletionStage of a Pair of the ResponseHeader with the response type.
In your code, the response type should be String, but you have defined it as Pair<ResponseHeader, String>, which means it expects the return value to be nested: CompletionStage<Pair<ResponseHeader,Pair<ResponseHeader, String>>>. Note the extra nested Pair<ResponseHeader, String>.
When used with HeaderServiceCall, which requires you to implement invokeWithHeaders, you get a compilation error, which indicates the mismatched types. This is the error in your screenshot above.
When you implement ServerServiceCall instead, your method is inferred to implement ServiceCall.invoke, which is defined as:
CompletionStage<Response> invoke()
In other words, the return type of the method does not expect the additional Pair<ResponseHeader, Response>, so your implementation compiles, but produces the incorrect result. The pair including the ResponseHeader is automatically serialized to JSON and returned to the client that way.
Correcting the code requires changing the method signature:
#Override
public HeaderServiceCall<LoginUser, String> login() {
return this::loginUser;
}
You also need to change the loginUser method to accept the RequestHeader parameter, even if it isn't used, so that it matches the signature of invokeWithHeaders:
public CompletionStage<Pair<ResponseHeader, String>> loginUser(RequestHeader requestHeader, LoginUser user)
This should solve your problem, but it would be more typical for a Lagom service to use domain types directly and rely on the built-in JSON serialization support, rather than serializing directly in your service implementation. You also need to watch out for null values. You shouldn't return a null ResponseHeader in any circumstances.
#Override
public ServerServiceCall<LoginUser, Pair<ResponseHeader, DebugTokenResponse.DebugTokenResponseData>> login() {
return this::loginUser;
}
public CompletionStage<Pair<ResponseHeader, DebugTokenResponse.DebugTokenResponseData>> loginUser(RequestHeader requestHeader, LoginUser user) {
try {
DebugTokenResponse.DebugTokenResponseData response = fbClient.verifyFacebookToken(user.getFbAccessToken(), config.underlying().getString("facebook.app_token"));
ResponseHeader responseHeader;
if (!response.isValid()) {
responseHeader = ResponseHeader.NO_CONTENT.withStatus(401);
} else {
responseHeader = ResponseHeader.OK.withStatus(200);
}
return completedFuture(Pair.create(responseHeader, response));
} catch (ExecutionException | InterruptedException | JsonProcessingException e) {
LOG.error(e.getMessage());
throw e;
}
}
Finally, it appears that fbClient.verifyFacebookToken is a blocking method (it doesn't return until the call completes). Blocking should be avoided in a Lagom service call, as it has the potential to cause performance issues and instability. If this is code you control, it should be written to use a non-blocking style (that returns a CompletionStage). If not, you should use CompletableFuture.supplyAsync to wrap the call in a CompletionStage, and execute it in another thread pool.
I found this example on GitHub that you might be able to adapt: https://github.com/dmbuchta/empty-play-authentication/blob/0a01fd1bd2d8ef777c6afe5ba313eccc9eb8b878/app/services/login/impl/FacebookLoginService.java#L59-L74
I'm implementing a custom Authentication Handler for wso2-am following this guide https://docs.wso2.com/display/AM190/Writing+Custom+Handlers
But it's not clear how to handle the case when my authentication handler returns false. The sample code of the handleRequest is
public boolean handleRequest(MessageContext messageContext) {
try {
if (authenticate(messageContext)) {
return true;
}
} catch (APISecurityException e) {
e.printStackTrace();
}
return false;
}
If I try calling an API with valid credentials everything goes well (the method returns true) and I get an "HTTP 200 OK" response. If I try with invalid credentials the method returns false but I get an HTTP 202 ACCEPTED" response. I would like to receive another response code (for example 400). How do I handle this authentication failure path?
Thank you.
Ideally you need to call handleAuthFaliure method with message context.
private void handleAuthFailure(MessageContext messageContext, APISecurityException e)
When you call that method please create APISecurityException object(as listed below) and pass it. Then error code and error messages will be picked from there and automatically send error to client(by default we return 401 for security exceptions and if defined then send defined error code and message).
public class APISecurityException extends Exception {
private int errorCode;
public APISecurityException(int errorCode, String message) {
super(message);
this.errorCode = errorCode;
}
public APISecurityException(int errorCode, String message, Throwable cause) {
super(message, cause);
this.errorCode = errorCode;
}
public int getErrorCode() {
return errorCode;
}
}
Hope this will work for you.
Thanks
sanjeewa.
i wrote a normal html login form, that forwards to a vaadin project, where i want to receive the username and password and check if its valid. but i have problems getting this request.
when i add a requesthandler in the init() method of my UI class, i can only get the request data after the second call of the vaadin page (because at the first call of init, the hander ist not added yet)
#Override
protected void init(VaadinRequest vaadinRequest) {
setContent(new MainComponent());
VaadinSession.getCurrent().addRequestHandler(
new RequestHandler() {
#Override
public boolean handleRequest(VaadinSession vaadinSession, VaadinRequest vaadinRequest, VaadinResponse vaadinResponse) throws IOException {
String username = vaadinRequest.getParameter("username");
return false;
}
});
so i tried to overwrite the VaadinServlet method doPost, but it does not get triggered. when i overwrite the methode service(HttpServletRequest request, HttpServletResponse response), this method is triggered a serval times for each request, so also not a good place to get just the userdata.
so whats the right way to solve this problem?
i dont't know if this is the best solution, but at least it works. maybe this helps someone.
here a short explanation what i do. i retrieve the posted username and password from the post values of my plain html login formular from another url and see if it is existing in the database. if it exists, it returns the result, otherwise the value ERROR.
i extended the VaadinServlet and overwrote the method service like this
#Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
super.service(request, response);
String username = request.getParameter("username");
if(username != null) { // called several times, only set when username is returned, otherwise the value remains "error"
String password = request.getParameter("password");
this.result = getResult(username, Encrypter.encryp(password));
}
}
and this is inside my class extended from UI
#Override
protected void init(VaadinRequest vaadinRequest) {
MyServlet myServlet = (MyServlet) VaadinServlet.getCurrent();
String result = myServlet.getResult();
if(result .equals(MyServlet.ERROR)){ // check if the result set in the servlet is valid, otherwise forward to the loginpage
goToLogin();
myServlet.resetResult();
return;
}
myServlet.resetResult();
...
}
To whom it may concern - obtaining request and response in Vaadin 8 (which might be also available in Vaadin 7):
VaadinServletRequest vsRequest = (VaadinServletRequest) VaadinService.getCurrentRequest ();
HttpServletRequest httpServletRequest = vsRequest.getHttpServletRequest ();
VaadinServletResponse vsResponse = (VaadinServletResponse) VaadinService.getCurrentResponse ();
HttpServletResponse httpServletResponse = vsResponse.getHttpServletResponse ();
You can read the request parameter directly through the VaadinRequest object that's passed into init():
#Override
protected void init(VaadinRequest vaadinRequest) {
setContent(new MainComponent());
String username = vaadinRequest.getParameter("username");
}
It work for me perfect:
User is my simple class with username, name etc.
setting logged user in session:
public void setLoggedUser(User loggedUser) {
this.loggedUser = loggedUser;
getUI().getSession().getSession().setAttribute("loggedUser", loggedUser);
}
reading user:
loggedUser = (User) getUI().getSession().getSession().getAttribute("loggedUser"); //return null if not logged in