AngularJS ajax resulting in two calls for html & json - angularjs

So I turned on network capture in my web browser to have a look at my ajax calls coming out of AngularJS. For every call made, there seems to be two results:
URL|Protocol|Method|Result|Type|Received|Taken
/p/jobs/03512dc8-6f25-49ea-bdff-0028ac2023cb|HTTP|GET|301|text/html|408 B|< 1 ms
/p/jobs/03512dc8-6f25-49ea-bdff-0028ac2023cb|HTTP|GET|200|application/json|0.79 KB|15 ms
It looks like it's attempting to request HTML first, getting a 301 and then requesting the JSON. How can I eliminate the request for HTML? I'm using $resource to do this but I'd also like to see an example for $http.
Also, the receiving framework is NancyFX for .NET. Perhaps there's a header I need to specify to make sure it always returns JSON? I've tried the "Accept" header but it seems to make no difference. It's as if Nancy is always trying to return a View first before switching to JSON.
Javascript code (translated slightly from TypeScript):
$resource(jobUrl, {}, { get: {method: "GET", isArray: false }});
Nancy code:
public class JobService : NancyModule
{
public static readonly string Prefix = "/p/jobs";
WebLogger logger;
public JobService(WebLogger logger)
: base(Prefix)
{
this.logger = logger;
Get[""] = _ => GetJobs();
Get["/{id}"] = _ => GetJob(_.id);
Get["/{id}/nodes"] = _ => GetNodes(_.id);
Get["/{id}/faults"] = _ => GetFaults(_.id);
}
Job GetJob(string id)
{
lock (logger)
{
if (logger.JobGuid != id)
{
Context.Response.StatusCode = HttpStatusCode.NotFound;
return null;
}
return MakeJob();
}
}

Some part of your code will be helpful, but lets try - you have put character / at the end of $resource definition. Angular has asked server for content for directory, server response with header 301 - redirect to file as Angular expects some data response than directory listing.

Related

using multiple parameters in get method from (axios) reactjs front-end to asp.net core webapi Back-end

I want to get shop by userId and userName if the shop for that user exists.
i have used the url in axios get call as follows:
const url = `${config.apiUrl}/api/Shops/`
useEffect(() => {
axios.get(url + `details?id=${user.id}&shopuser=${user.username}`)
.then((res) => {
setShop(res.data);
})
.catch((error)=>{
console.log(error);
}
)
At the back-end asp.net core web api I have used the following action Method:
[HttpGet("{dashboard}")]
public async Task<ActionResult<Shop>> Dashboard(int id,string shopuser)
{
var shop = await _context.Shops.FirstOrDefaultAsync(a=>a.UserId==id && a.UserName==shopuser);
if (shop == null)
{
return NotFound();
}
return shop;
}
The problem is that the call is not sent to this action method with correct parameters and hence the response with error error 500 .
The controller name is as follows:
{
[Route("api/[controller]")]
[ApiController]
public class ShopsController : ControllerBase
{
.......
....
}
}
I have checked the Network tab of console the parameters are sent as follows:
/api/Shops/details?id=1&shopuser=asifranjha
thanks in advance for help.
[HttpGet("{dashboard}")] annotation means that your get request is expecting a route parameter (dashboard).So if you want to trigger your method, you should call /api/Shops/1?shopuser=asifranjha (I recommend you to keep the same naming so you should change dashboard to id or the opposite, you could also provide the type for your route with route constraints).
If you want to use /api/Shops/details?id=1&shopuser=asifranjha, you should just change your annotation parameter so it would look like this: [HttpGet("details")] and everything should work.Good luck with your project!

Upload file from AngularJS to Spring Boot

I'm using AngularJS to make my front end and Java with Spring Boot to make my back end. I'm trying to import/upload a xlsx, xls, or ods file from the Angular to my Java, but whatever I do, the request doesn't send my file!
Java endpoint:
#PostMapping(value = "/upload/{type}")
#ResponseBody
private ResponseEntity<List<Rota>> importFile(#PathVariable("type") String type,
#RequestParam(required = false, value = "file") MultipartFile fileParam,
#RequestBody MultipartFile file) {
System.out.println("File: " + file.getName());
if(type.toUpperCase().equals("XLSX")){
System.out.println("XLSX!");
}else if(type.toUpperCase().equals("XLS")){
System.out.println("XLS!");
}else if(type.toUpperCase().equals("ODS")){
System.out.println("ODS!");
}else{
System.out.println("OPS!");
return new ResponseEntity<>(new ArrayList<>(), HttpStatus.UNSUPPORTED_MEDIA_TYPE);
}
return new ResponseEntity<>(new ArrayList<>(), HttpStatus.OK);
}
My request-id made using an Angular class prepared to only make requests. I'll post here the code that we use normally in the project and the code that actually worked but I can't use it.
DataFactory:
DataFactory.POST = function (url, entity, config = null) {
if (url && entity) {
return $http
.post(url, entity, config)
.then(res => $q.resolve(res.data), error => $q.reject(error));
}
};
The code that actually worked:
var xhr = new XMLHttpRequest;
xhr.open('POST', `${URL.CTM_ODS()}/rotas/upload/${type}`, true);
xhr.send(formData);
When I use Postman, sending the file through the body, the back end receives null, but when I use form-data from Postman, works fine!
Using the DataFactory I got the following stack on my back end:
WARN 16796 --- [p1002886236-126] org.eclipse.jetty.http.HttpParser : badMessage: java.lang.IllegalStateException: too much data after closed for HttpChannelOverHttp#78fd8670{r=2,c=false,a=IDLE,uri=}
Found the answer in this video: https://www.youtube.com/watch?v=vLHgpOG1cW4
My problem was that the AngularJS deserialize the file! So, what I've made was just put a config object saying to not do that:
DataFactory.POST(`${URL.CTM_ODS()}/rotas/upload/${type}`, formData, { transformRequest: angular.indentity, headers: { 'Content-Type': undefined } }).then(response => {
delete vm.importacao.arquivoCsv;
console.log('Response: ', response);
LoadingManager.hide();
});
As you can see, the difference is on the header object, can you see that we pass the content type as undefined and transformRequest: angular.indentity? That worked for me! If anyone has other way to do so, feel free to comment! Thanks and have a nice day!

How to handle GZip/Deflate on HTTP Actions

I have an HTTP Action in Azure Logic Apps that calls a StackExchange API, fundamentally, it could be any API that returned GZip or Deflate content by default:
Because the response is neither Plain Text nor JSON the output from the HTTP Action is:
{
"$content-encoding": "gzip",
"$content-type": "application/json; charset=utf-8",
"$content": "H4sIAAAAAAAEAGWPzY7CMAyE38XnqsrPFtq+ClpFoXghEkm6iVtWQrw7Lt3mAEd/Hs+M7+AIfYb+cIeAN2MHcjOaKWNiKCqgSPa6zZ2SFRzt6YzZjJiMd2EiZF0tvjbpuoZe7rrdxuZIC9KNLo5D9B4DLUIl2gpsyDfOeLflvN8JM7kYPnbF6/+WA/ZNYcOAI+Hp5V/eCKv0heVGSwD0SnRcZXQm4ewyM+hBCbmvda3aWjVaS3h8V3Cx2fiYuMePvWZcSrKV8faPSyzF1jmhty64cGbnVjyeRIHcnG0BAAA="
}
If you went to the trouble of passing the $content field through #base64toString() you would end up with the Gzip binary representation of the JSON, and that is as far as I can take it.
Question: How can I either force the HTTP Action to behave like a HttpClient and Accept GZip data and emit the JSON from the Action, or more laboriously take the GZip Base64/Binary data and decompress it before acting further upon it?
I wasn't able to find a way to "solve" the problem directly, so I created an Azure Function that made the request to the URL with the appropriate HttpClientHandler passed into the HttpClient:
#r "Newtonsoft.Json"
using System;
using System.Net;
using Newtonsoft.Json;
public static async Task<object> Run(HttpRequestMessage req, TraceWriter log) {
string jsonContent = await req.Content.ReadAsStringAsync();
dynamic data = JsonConvert.DeserializeObject(jsonContent);
if (data.url == null) {
return req.CreateResponse(HttpStatusCode.BadRequest, new {
error = "Please pass a URL in the input object"
});
}
HttpClientHandler handler = new HttpClientHandler() {
AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};
var client = new HttpClient(handler);
var result = await client.GetAsync((string)data.url);
var response = req.CreateResponse(HttpStatusCode.OK);
response.Content = result.Content;
return response;
}
By swapping the built-in HTTP Action from the original question, I was able to get this working:
And the configuration for the Azure Function is as follows:

Doing a GET passing a complex object with angular

I am using AngularJs and Resources module. I want to do a GET to obtain an object.. to do this GET I do not have to pass simply the ID to the server, but I should pass a complex object with different properties and values..
Here the code I am using:
$scope.getActivationStatus = function (event) {
event.preventDefault();
if ($scope.segui_attivazione_form.$valid) {
$scope.activationStatus =
new SeguiAttivazioneService
.seguiAttivazione()
.$get(
{
request: $scope.activationStatus
}, function () { });
}
};
On server side I have:
[HttpGet]
public IHttpActionResult GetActivationStatus(MyComplexObject request)
{
//I will do something here later...
return Ok();
}
The problem is that "request" arrive on server equals to NULL...
I have solved the problem passing two strings to the server... in this way:
$scope.getActivationStatus = function (event) {
event.preventDefault();
if ($scope.segui_attivazione_form.$valid) {
$scope.activationStatus =
new SeguiAttivazioneService
.seguiAttivazione()
.$get(
{
codiceFiscale: $scope.activationStatus.CodiceFiscale,
codiceRichiesta: $scope.activationStatus.CodiceRichiesta
}, function () { });
}
};
And server side:
[HttpGet]
public IHttpActionResult GetActivationStatus(string codiceFiscale, string codiceRichiesta)
{
return Ok();
}
In this way everything works... but I don't like this solution because I will have more than two input...
And this is a get, not a post (not a save, an update)...
How can I pass a complex object doing a GET?
Thank you...
It's best to use the POST method if you want to send data in the body of the request. While it's possible with Angular, some servers might ignore the body of GET requests.
This approach allows to send complex objects with arrays and sub objects:
Angular:
$http({
url: '/myApiUrl',
method: 'GET',
params: { param1: angular.toJson(myComplexObject, false) }
})
C#:
[HttpGet]
public string Get(string param1)
{
Type1 obj = new JavaScriptSerializer().Deserialize<Type1>(param1);
...
}
This is not an elegant solution but it works using HTTP GET:
$http.get(url + "?" + $.param(obj).replace(/%5b([^0-9].*?)%5d/gi, '.$1'))
It converts the complex object into a string with dot notation to define levels. Most of the server side frameworks like ASP.NET Core can bind it to complex objects.
This is an example of the string I send for a complex object:
StartDate=2021-06-11&EndDate=2021-06-11&TimeRange.TimeFrom.Time=07%3A00&TimeRange.TimeFrom.TimeFrame=AM&TimeRange.TimeTo.Time=10%3A00&TimeRange.TimeTo.TimeFrame=AM
Request body can only be sent by POST. With get you could at best URL Encode the OBJECT and then send it as query string params. But thats not the best solution to post some data to the server

415 (Unsupported Media Type) in $http.post method

I'm quite new to REST and AngularJS, but after several hours of googling I couldn't find any answer to my question:
I'm trying to do a POST request from my angularjs frontend to my backend implemented in java (using JPA).
When I'm trying to create a json-object and to do a POST I always get the 415 (Unsupported Media Type) error.
(Actually I don't even get "into" the scope of the service (i.E. "IN SERVICE" doesn't get printed to the console)..
If I add postData.toJSON(), it actually gets "POSTed", but arrives null ...
how do I have to format my 'postData' in Order to succesfully get POSTed?
(I also tried to write the Date-properties without ' " ' - no luck...)
Thank you for your help!
FrontEnd:
app.controller('WorkController', function($scope, $http) {
$scope.saveWork = function () {
var postData = {
"status" : "OPEN",
"startDate": "1338364250000",
"endDate": "1336364253400",
"WorkText" : "Test"
};
$http.post("http://localhost:8080/service/v1/saveWork", postData)
.success(function(data, status, headers, config){
console.log("IN SAVE WORK - SUCCESS");
console.log(status);
})
.error(function(){
console.log("ERROR IN SAVE WORK!");
})
}
});
Service:
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response save(WorkDto wo){
System.out.println("IN SERVICE");
if(ass == null){
System.out.println("Could nor persist work- null");
return Response.noContent().build();
} else{
Work workDao = WorkTransformator.transform(wo);
workDao.persist();
return Response.ok().build();
}
}
Instead of building and sending a parsed JSON object, create a javascript object and send that in your post body. You can reuse your postData object, but try removing the "" surrounding properties names.
Try this:
var postData = {
status : "OPEN",
startDate: "1338364250000",
endDate: "1336364253400",
workText : "Test"
};
UPDATE
Looks like the above doesn't work by itself. I thought that the Content-Type would be infered.
Can you try to do the post request this way :
$http({
method: 'POST',
url: 'http://localhost:8080/service/v1/saveWork',
data: postData,
headers: {
'Content-Type': 'application/json'
}}); // complete with your success and error handlers...
// the purpose is to try to do the post request explicitly
// declaring the Content-Type you want to send.
UPDATE 2
If this didn't work, compose a post request using Fiddler, and check what's the response.
Here's some pointers:
Download Fiddler2 if you dont already have it
Compose a request like in the screenshot below
You can then check on the pane on the left for what was the server response code. Double click that line (Ignore the error code on the screenshot...you should be getting a 415)
After double-clicking the response line, you can check and browse for more details on the right pane:
If you can successfuly post with a «manufactured» JSON object then the problem resides on your Angular code. If not, it's certainly something wrong with your Rest Service configuration.
You can also inspect the details of your POSTS made with the Angular app in Fiddler2. That should give you a good insight of what's going on.
If you're into it, you can then update your question with some screenshots of your Angular app requests. That will certainly help us to help you :)
I finally managed to find the cause of my error!
In my Rest-Service, I directly expected my java-class as parameter. (I thought this would be parsed/deserialized automatically). Quite naive I think... :)
In order to get it working I had to:
-Expect a String as Parameter in my #POST service
-Deserialize it (using GSON)
Here is the (now working) service:
#POST
#Consumes(MediaType.APPLICATION_JSON)
public Response save(String wo){
if(wo == null){
System.out.println("Could nor persist work- null");
return Response.noContent().build();
} else{
Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HHmm:ssZ").create();
WorkDto dto = gson.fromJson(wo, WorkDto.class);
Work workDao = WorkTransformator.transform(dto);
workDao.persist();
return Response.ok().build();
}
}
Thanks again António for your help!

Resources