Play Framework 2.x always send single response code - web

Hopefully you guys can help me with this! I have a problem where I need to send a constant response code no matter what the request contains. If the request has bad JSON etc. The response I need to send is a 204 (No Content)
Here's my code where I try to send back a no content header.
public Result response(){
RequestBody body = request().body();
System.out.println(body.asJson());
return noContent();
}
Now if I try and send a request containing JSON like below. It returns a 400 (Bad request). I want to send a 204 no matter what. Please let me know what you guys come up with.
JSON POST
{
"mike":"mike
}
Thanks
Edit:
Sorry I replaced one of these lines of code and forgot to update this. Above I only return 204's, but if my client sends me bad JSON then I still return a 400.

You need to modify the global settings for play.
Create a class that extends Global Settings and override whichever method you want.
public class Global extends GlobalSettings {
#Override
public Promise<Result> onBadRequest(RequestHeader arg0, String arg1) {
super.onBadRequest(arg0, arg1);
return F.Promise.promise(()->{return play.mvc.Results.noContent();});
}
}
For more information : https://www.playframework.com/documentation/2.4.x/JavaGlobal

To return 204, you can use noContent method
For that replace ok() by noContent()

Try this,
#BodyParser.Of(BodyParser.Json.class)
public static Result response() {
JsonNode json = request().body().asJson();
if(json == null){
return noContent();
}else{
// Get json content from request and process rest..
}
return ok("");
}
By using above approach, a 204 HTTP response will be automatically returned for non JSON requests.

Related

Angular post to ASP.NET Core 6 gets 400 while Postman works fine

Originally I tried to send the argument as an object, but in ASP.NET Core 6, it is failing (400 error). From the many answers, I decided to stringify the object to a string and pass it like this:
var dtoAsJson: string = JSON.stringify(this.projectCreateInitDto);
this.http.post<ProjectDto>(baseUrl + 'Projects/CreateProject/', dtoAsJson).subscribe({
next: (response: ProjectDto) => {
Stopping on the http.post, dtoAsJson was a text string of course.
The controller looks like this:
[Route("CreateProject")]
[HttpPost("{Jsondto}")]
public async Task<ActionResult<ProjectAPIDto>> CreateProject(string Jsondto)
{
ProjectAPICreateInitDto dto = Json.Decode<ProjectAPICreateInitDto>(Jsondto);
Project project = _mapper.Map<Project>(dto);
}
I stop on the Json.Decode and Jsondto is null.
I've searched for solutions, but I'm stuck.
Thoughts? Thanks in advance
The problem is that you are sending the dtoAsJson-object as the body of the POST request, but in the backend you are trying to receive it as a route parameter.
You could try the following:
[Route("CreateProject")]
[HttpPost]
public async Task<ActionResult<ProjectAPIDto>> CreateProject([FromBody] string Jsondto)
{
ProjectAPICreateInitDto dto = Json.Decode<ProjectAPICreateInitDto>(Jsondto);
Project project = _mapper.Map<Project>(dto);
}
Hint how to further improve your code:
I suppose your code will work without JSON.stringify(), if you use [Route("CreateProject")] and [FromBody] in the backend.

How to set content type for WebFluxRequestExecutingMessageHandler

I am trying to make an HTTP POST request to an external service using WebFluxRequestExecutingMessageHandler, and I am having a lot of trouble getting the Content-Type header set for the outbound request. By default it sets the Content-Type to x-java-serialized-object, but the service I'm hitting only accepts application/json. The only way around this I have found so far is to pass in a custom HeaderMapper:
webFluxRequestExecutingMessageHandler.setHeaderMapper(object : HeaderMapper<HttpHeaders> {
override fun toHeaders(source: HttpHeaders): MutableMap<String, Any> {
return mutableMapOf()
}
override fun fromHeaders(headers: MessageHeaders, target: HttpHeaders) {
target.contentType = MediaType.APPLICATION_JSON
}
})
Is there a better way to accomplish this?
Thanks.
The DefaultHttpHeaderMapper.outboundMapper() has an ability to map a:
case "contenttype": // Lower case for MessageHeaders.CONTENT_TYPE
setContentType(target, value);
to the Content-Type HTTP header. So, you can try to set that MessageHeaders.CONTENT_TYPE message header upstream before sending the message to this WebFluxRequestExecutingMessageHandler.
That x-java-serialized-object is not a standard MimeType, so I guess you have a configuration like WebFluxRequestExecutingMessageHandler.setExtractPayload(false), which means try to send the whole Message<?> over HTTP. Not sure if that is what you want to achieve because the Message<?> is not fully JSON compatible...

ServiceStack NativeTypesFeature AddResponseStatus

I'm writing a backend using ServiceStack. our main front end client is an Angular 2 application using TypeScript. To that end, we are using the DTOs that are generated by the services when hitting /types/typescript and /types/typescript.d. This all works fine and good using the JsonServiceClient... but it seems that the response status code is somehow wrapped up in the call and not returned as it as when using a standard XHR call.
Finding the AddResponseStatus configuration item, I changed the service configuration to add this on any DTO that didn't already have the property (which mine didn't):
var ntf = new NativeTypesFeature();
ntf.MetadataTypesConfig.AddResponseStatus = true;
Plugins.Add(ntf);
After refreshing the TypeScript reference, I can see that all DTO types returned now have a ResponseStatus property on them.
export class QueryReportResponse
{
Data: string;
ResponseStatus: string;
}
Here is a scrubbed return (removed the 'Data' portion) showing the property exists on the object:
<QueryReportResponse xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/blah.blah.ServiceModel.Messages">
<Data>
blah blah data here
</Data>
<ResponseStatus i:nil="true"/>
</QueryReportResponse>
Now, I assumed (wrongly so) that by doing this, some sort of status would be set 'automatically'. I'm obviously not right here, as this property is not set. My front end guy is asking to be able to see the status on all returned calls, like he was able to before when using straight XHR prior to using the JsonServiceClient, as now he cannot see the return status.
What is the intent of this field? I cannot set it manually, as it's added by ServiceStack dynamically at runtime. I can only assume that I would have to create my own base class return DTO of sorts and set that on the way back to the caller... can someone help me understand the purpose of this field? Thanks.
ServiceStack's Add TypeScript Reference is typically used with the TypeScript servicestack-client. The ResponseStatus is used in ServiceStack's Error Handling which is used to capture structured Error Information. It's not populated for successful responses and it's distinct from the HTTP Response Status code although if throwing a HTTP Error the ResponseStatus.ErrorCode will typically contain the HttpStatusCode enum string.
Adding ResponseStatus on DTOs
Adding the ResponseStatus on DTOs, e.g:
ntf.MetadataTypesConfig.AddResponseStatus = true;
Just adds the ResponseStatus on generated DTOs where they didn't previously exist. It doesn't have any effect on Response DTOs which already includes the ResponseStatus property, e.g:
public class MyResponse
{
public ResponseStatus ResponseStatus { get; set; }
}
Accessing HTTP Status Responses
Developers shouldn't care what the HTTP Status code is for successful responses (which is almost always 200 OK). ServiceStack's TypeScript JsonServiceClient will just return the Typed Response DTO for successful responses, e.g:
var response = await client.post(request)
They should only be interested for handling error responses, however it's expected to use the ResponseStatus.ErrorCode to determine the type of Error and apply application error handling logic, e.g:
try {
var response = await client.post(request)
} catch (e) {
console.log(e.responseStatus.errorCode);
}
If they really want the HTTP Status they can get it using a response filter, e.g:
var status = null;
try {
client.responseFilter = res => status = res.status;
var response = await client.post(request)
} catch (e) {
console.log(status, e.responseStatus.errorCode);
}

Server Cannot Append Header After HTTP headers have been sent Exception at #Html.AntiForgery

I'm developing an asp.net mvc 5 application in which I was trying to redirect to the ReturnUrl by applying the code below :
[HttpPost]
[AllowAnonymous]
public ActionResult Login(UserLogin model, string returnUrl)
{
if (ModelState.IsValid)
{
string EncryptedPassword = GetMD5(model.Password);
if (DataAccess.DAL.UserIsValid(model.Username, EncryptedPassword))
{
FormsAuthentication.SetAuthCookie(model.Username, true);
if (String.IsNullOrEmpty(returnUrl))
{
return RedirectToAction("Index", "Home");
}
else
{
Response.Redirect(returnUrl);
}
}
else
{
ModelState.AddModelError("", "Invalid Username or Password");
}
}
return View();
}
The above code is working fine, But the problem is that when I Post the login form, it gives me an Exception that I've never faced Before and I'm having difficulties resolving the exception that is generating in the view in Login.cshtml, At Line :
#Html.AntiForgeryToken()
And the Exception That it throws:
Server cannot append header after HTTP headers have been sent.
I've researched a lot but I'm unable to get to the conclusion. My application works fine when I remove #Html.AntiForgeryToken() line, But I don't want to do this, I want my application to remain cross-site request protected.
Can Anyone Please Help me out, How do I get rid of this Exception?
When Response.Redirect(anyUrl) the status code is set to 302, and the header will added to the response :
HTTP 1.0 302 Object Moved
Location: http://anyurl.com
And when ViewResult is executed and razor render the view the Html.AntiForgeryToken() will called, so the helper tries to add the header X-Frame-Options and some cookies to the response, it is the cause of the exception.
But don't worry you can suppress the addition of X-Frame-Options header, just put this AntiForgeryConfig.SuppressXFrameOptionsHeader = true; in the Application_start.
But I suggest you to change this:
Response.Redirect(returnUrl);
to
return Redirect(returnUrl);
Note
Since .NET code was opened you can see how the AntiForgeryToken works, see here AntiForgeryWorker.
I was getting same error with Response.Redirect(returnUrl). After changing to Response.Redirect(returnUrl, false) fixed the issue.

How to return only status code in POST request in servicestack Instead of HTML page

have created REST service using servicestack and in post request I have return object in following way
return new HttpResult(request)
{
StatusCode = HttpStatusCode.Created,
};
request: object which i have posted in database
When i check it in fiddler it render whole HTML Page of servicestack in response body, instead of that i would like to return Status code only, so please tell me how can i do?
Thanks
There was a bug in versions before < v3.05 that did not respect the HttpResult ContentType in some scenarios, it should be fixed now with the latest version of ServiceStack on NuGet or available from:
https://github.com/ServiceStack/ServiceStack/downloads
Prior to this you can still force the desired ContentType by changing the Accept:application/json Request Header on HttpClient or by appending ?format=json on the querystring of your url.
So now if you don't want to have any DTO serialized, you don't add it to the HttpResult:
return new HttpResult() { StatusCode = HttpStatusCode.Created };
Note you still might get an empty Html response back if calling this service in the browser (or any Rest Client that Accepts:text/html). You can force a ContentType that won't output any response if it has empty payload (e.g JSON/JSV) by specifying it in the result as well, e.g;
return new HttpResult() {
StatusCode = HttpStatusCode.Created,
ContentType = ContentType.Json
};

Resources