Http POST 405 errror in Angularjs with Spring MVC - angularjs

Actually I want to integrate Spring with Angularjs and i am beginner in Angularjs. When i use $http post method it return POST 405.Here is my code
SignUp.html
<form method="post" ng-submit="saveUser()">
<input type="hidden" name="${_csrf.parameterName}"
value="${_csrf.token}" />
</form>
myApp.js
var myApp = angular.module('myApp', ['ngMessages']);
UserIdController.js
myApp.controller('UserIdController', [
'$scope',
'UserIdService',
function($scope, UserIdService) {
$scope.saveUser = function() {
UserIdService.saveUser($scope.user).then(
function success(response) {
console.log("user Added");
}, function error(response) {
console.log("User not Added")
});
}
} ]);
UserIdService.js
myApp
.service(
'UserIdService',
[
'$http',
function($http) {
this.saveUser = function saveUser(user) {
return $http({
method : 'post',
url : 'SignUpUser',
data : {
firstName : user.firstName
},
headers : 'Content-Type: application/json'
});
}
} ]);
Spring REST Controller
#RestController
#Produces("text/plain")
public class SignUpController {
private static final Logger logger =
LogManager.getLogger(SignUpController.class);
#RequestMapping(value = "/SignUpUser", method =
RequestMethod.POST, headers = "Accept=application/json")
public String saveUser(#PathVariable String firstname) throws
ParseException {
logger.debug("Enter in SignUp Controller in Post Method");
UserDetails userDetails = new UserDetails();
studentDetails.setFirstName(firstname);
return "ok";
}
I got this error in Chrome in Inspect element
Request URL:http://localhost:8080/examapp/signup
Request Method:POST
Status Code:405
Remote Address:[::1]:8080
Referrer Policy:no-referrer-when-downgrade
Response Headers
view parsed
HTTP/1.1 405
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-XSS-Protection: 1; mode=block
X-Frame-Options: DENY
X-Content-Type-Options: nosniff
Allow: GET
Content-Type: text/html;charset=ISO-8859-1
Content-Language: en
Content-Length: 1084
Date: Fri, 04 Aug 2017 05:50:32 GMT
Request Headers
view source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate, br
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:26
Content-Type:application/json
Cookie:JSESSIONID=ACF3E30CB7B3A6A9862F923F42DB61B5
Host:localhost:8080
Origin:http://localhost:8080
Referer:http://localhost:8080/examapp/signup.html
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36
Request Payload
Does anyone have an idea of what I'm doing wrong? It seems like a pretty straight forward implementation that is working on all of the tutorials I've seen yet. Any help will be appreciated. Thank you.

Please add #RequestMapping("/examapp") over yourSignUpController
#RestController
#Produces("text/plain")
#RequestMapping("/examapp")
public class SignUpController {

You have specified #PathVariable here. A path variable is just that, a variable from the path. What you want is #RequestBody.
In your scenario, Spring has nothing maped to /SignUpUser, it is looking for /SignUpUser/{firstName}, but since #RequestMapping doesn't specify {firstName}, you are essentially posting to a non-existent resource.
Although unrealistic in the real world, to post just a first name to login, In your $http.post, you would just want data : user.firstName.
In your Spring controller:
#RequestMapping(value = "/SignUpUser", method =
RequestMethod.POST, headers = "Accept=application/json")
public String saveUser(#RequestBody String firstname)
The Right Fix
If you want your back-end to accept what you have in Angular (more real-world), you would create a POJO class, and accept that (#RequestBody UserDetails request). It appears you have the UserDetails POJO created, so you just have to accept that instead:
#RequestMapping(value = "/SignUpUser", method =
RequestMethod.POST, headers = "Accept=application/json")
public String saveUser(#RequestBody UserDetails userDetails ) {

Related

Angular $http.post 1.6.1 not passing data to WebAPI

All, I just created a new Angular package using 1.6.1 but now the data doesn't seem to pass to my WebAPI. However, when I post bits via SoapUI or something like that, everything is fine.
The Javascript looks like this:
function testapi()
{
var serviceRoot='http://server/testangular16/api/Values';
var deferred=$q.defer();
var req = {
method: 'POST',
url: serviceRoot,
data: 'PassInTheText'
};
$http(req).then(goodResponse,badResponse);
return deferred.promise;
};
function goodResponse(response)
{
console.log("Good response");
console.log(response);
}
function badResponse(response)
{
console.log("Bad response");
console.log(response);
}
and the webapi is a very simple C# controller:
// POST api/values
public HttpResponseMessage Post([FromBody]string value)
{
HttpResponseMessage rp = new HttpResponseMessage(HttpStatusCode.OK);
rp.Content = new StringContent(value);
return rp;
}
I am making it into the controller, I can set a break point and hit the parts where I can look at the value. It's always null.
Looking at the network trace, the angular part does do a preflight and I can see the 200 response back.
Request URL:http://server/testangular16/api/Values
Request Method:OPTIONS
Status Code:200 OK
Remote Address:10.7.14.209:80
**Response Headers view source**
Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:content-type
Access-Control-Allow-Origin:http://localhost:8000
Cache-Control:no-cache
Content-Length:0
Date:Fri, 03 Feb 2017 18:09:04 GMT
Expires:-1
Pragma:no-cache
Server:"Management Corporation"
X-AspNet-Version:4.0.30319
**Request Headers view source**
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:en-US,en;q=0.8
Access-Control-Request-Headers:content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:mjvzrx3
Origin:http://localhost:8000
Referer:http://localhost:8000/
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36
So, it looks like I'm passing CORS, but when I get to trying to pass the data in as the content of the post, it doesn't make it.
Any ideas what I'm missing?
Thanks,
Nick
Web API expects an object in the message body, you cant pass in a primitive type unless you use application/x-www-form-urlencoded as the content-type and prefix the value with an equals = sign.
So you can fix it by one of these methods
Adjust the c# parameter and turning it into a type that has a string property and then send in a json object with a matching parameter name.
Change the request to url-encoding content type and add a = to the variable value.
Send it as a part of the URL instead of the message body, you can still use the POST method.
Change to form-urlencoded
function testapi()
{
var serviceRoot='http://server/testangular16/api/Values';
var deferred=$q.defer();
var req = {
method: 'POST',
url: serviceRoot,
data: '=PassInTheText', // added =
contentType: 'application/x-www-form-urlencoded' // specify content type
};
$http(req).then(goodResponse,badResponse);
return deferred.promise;
};
It seems if I do this, it works as expected.... Thoughts?
// POST api/values
public HttpResponseMessage Post(HttpRequestMessage request)
{
var data = request.Content.ReadAsStringAsync().Result;
Console.WriteLine("Data: {0}", data);
HttpResponseMessage rp = new HttpResponseMessage(HttpStatusCode.OK);
rp.Content = new StringContent("Data back from WebAPI" + data);
return rp;
}

unsupported Media type 415 for file upload with Spring mvc restcontroller and angularjs

When i am trying to hit the angularjs $http.post which contains file upload details its giving me unsupported media type. I am using backend spring mvc rest controller. The following is the code snippet.
<ul><li><h4>Document Type</h4>
<select name="docType" ng-model="docType" name="docType">
<option value="Report1">Report1</option>
<option value="Report2">Report2</option>
</select>
<input type="file" ng-model-instant id="fileToUpload" onchange="angular.element(this).scope().setFiles(this)" />
</li>
<li><h4>Comments:</h4><textarea></textarea></li>
<li><button class="btn-panel-blue" type="submit">Saves</button></li>
<li>Cancel</li>
</ul>
angular.module('app')
.controller('prjCntrl', function ($scope,projectService, sharedService, $location, $log, $http, $state) {
$scope.setFiles = function(element) {
$scope.$apply(function(scope) {
$scope.uploadedFile ;
for (var i = 0; i < element.files.length; i++) {
$scope.uploadedFile=element.files[i];
break;
}
});
};
$scope.updateProject = function updateProject()
{
var formData=new FormData();
formData.append('docType',angular.toJson($scope.projectData.docType,true));
formData.append("uploadFile",$scope.uploadedFile);
var url=baseURL + '/updateProject.do';
$http.post(url, formData, { transformRequest: angular.identity, headers: {'Content-Type': undefined} })
.success(function(){alert("success");})
.error(function(){ });
};
}
);
and here is my java code.
#RestController
#MultipartConfig(fileSizeThreshold=1024*1024*10,
maxFileSize=1024*1024*50,
maxRequestSize=1024*1024*100)
public class ProjectController {
#RequestMapping(value="/updateProject.do",method = RequestMethod.POST,headers ="Accept=multipart/form-data", consumes={"multipart/form-data"}, produces={"text/plain;charset=UTF-8"})
public #ResponseBody String updateProjectDetails(HttpServletRequest request, HttpServletResponse response, #RequestBody ProjectForm command)
{
contractProjectsService.saveProject(command);
return "success";
}
}
here is the header information from chrome headers/request and response data
**General:**
Request URL:http://localhost:9090/SpringMVCAngularJS/updateProject.do
Request Method:POST
Status Code:415 Unsupported Media Type
Remote Address:[::1]:9090
***Response Headers:***
view source
Content-Language:en
Content-Length:1048
Content-Type:text/html;charset=utf-8
Date:Wed, 03 Aug 2016 15:06:05 GMT
Server:Apache-Coyote/1.1
***Request Headers:***
view source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Authorization:Basic YmVlcDpib29w
Connection:keep-alive
Content-Length:1011
Content-Type:multipart/form-data; boundary=---- WebKitFormBoundaryagdf0LOX4AuXY6SI
Cookie:JSESSIONID=96052E348C6E52F53A594A179E65DE6D
Host:localhost:9090
Origin:http://localhost:9090
Referer:http://localhost:9090/SpringMVCAngularJS/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36
Please help me with the solution.
try to send the comment or other data in request header and send file to contoller ,in controller use" #Requestpart" for accepting file. Use below code for reference..
#Produces("text/plain;charset=UTF-8")
#RequestMapping(value = "/fileUpload/", method = RequestMethod.POST)
public #ResponseBody ResponseCodeModel fileUpload(#RequestPart MultipartFile file,
#RequestHeader(value = "comment") String comment,
)

ASP.NET WebApi Answer 400 Bad Request to OPTIONS on ValidateClientAuthentication, even on context.Validated()

I have an angularjs HTML client to a WebApi project. When I test the APIs via POSTMAN or other REST Client, it seems that everything is ok.
When I start using browsers with my angularjs client, browsers always start preflight requests with OPTIONS. There, my WebAPI always answers 400 Bad Request - I am still on a "/api/token" phase.
I have already attached every single point of my WebAPI project to the debugger. I have also changed several points according to several answers here in SO on how to enable CORS. Some of them I have already tried: changing web.config to add headers enabling cors on every request, adding cors to WebApi startup, enabling cors at "/token" overridden functions.
Here is what I got so for:
Angularjs TypeScript call to "/api/token":
logIn = (userName: string, userPassword: string): ng.IPromise<void> => {
var postData = {
"grant_type": "password",
"client_id": this.appConfiguration.ClientId,
"client_secret": this.appConfiguration.ClientSecret,
"username": userName,
"password": userPassword
};
return this.$http.post<models.LoggedUserModel>('http://local.web.api/api/token', $.param(postData), {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
}
}).then((result) => {
this.localStorageService.set('Auth', result);
this.goHome(true);
}).catch((error) => {
console.warn(error);
});
}
Here is the only function that is called on my WebApi:
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// handle cors requests
if (!string.IsNullOrEmpty(context.OwinContext.Request.Headers.Get("Origin")))
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new string[] { "*" });
}
try
{
// retrieve clientId and clientSecret from request body
string clientId;
string clientSecret;
if (context.TryGetFormCredentials(out clientId, out clientSecret))
{
// here it comes our application specific security code....
}
else
{
// this is part of enabling CORS..
if (context.Request.Method.ToUpper() == "OPTIONS")
{
// it returns OK to preflight requests having an empty body
context.Validated();
}
}
}
finally
{
// log stuff...
}
}
If I just left OWIN Cors stuff, adding headers and calling ´context.Validated()´ it all continues the same. Here is what I get:
Firefox Network Tab:
--------------------
Request URL: http://local.web.api/api/token
Request method: OPTIONS
Remote address: 127.0.0.1:80
Status code: 400 Bad Request
Version: HTTP/1.1
Request headers:
----------------
Host: local.web.api
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.7,pt-BR;q=0.3
Accept-Encoding: gzip, deflate
DNT: 1
Access-Control-Request-Method: POST
Access-Control-Request-Headers: authorization
Origin: http://local.web.client
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Response headers:
-----------------
Access-Control-Allow-Origin: *
Cache-Control: no-cache
Content-Length: 34
Content-Type: application/json;charset=UTF-8
Date: Tue, 22 Dec 2015 15:24:23 GMT
Expires: -1
Pragma: no-cache
Server: Microsoft-IIS/10.0
X-Powered-By: ASP.NET
I would really appreciate some ideas of where to got.
This is brand new to me, and I do operate some other WebApi projects + angularjs.
Ok, that's is terrible but I found the issue.
I am using a http interceptor on angularjs that would automatically check for a logged user and add an Authorization header with the Bearer token when needed. Problem is I was doing it wrongly.
I created a new property in the config object, bypassToken as boolean, that would be the flag to add or not the Authorization header. Removing this actually fixed the code. Not sure why, but analyzing the request now I can see that all headers are actually sending as expected: with the Content-Type which was not being filled on the first case correctly. Weird though no warning was thrown by angularjs.
// http auth interceptor
angularApplication.factory('httpAuthInterceptor', ['$rootScope', '$injector', '$location', ($rootScope, $injector, $location): ng.IHttpInterceptor => {
var $q: ng.IQService = $injector.get('$q');
var localStorageService: ng.local.storage.ILocalStorageService = $injector.get('localStorageService');
return {
request: (config: ng.IRequestConfig): ng.IRequestConfig => {
// check if headers are present
config.headers = config.headers || {};
// the error was here! I was trying to add properties to config that I think angular was not expecting
// removing this line solved the issue
// if (!config.bypassToken) {
// check if user is logged in
var loggedUserInfo = localStorageService.get<models.LoggedUserInfoModel>('Auth');
if (loggedUserInfo) {
config.headers['Authorization'] = 'Bearer ' + loggedUserInfo.access_token;
}
return config;
},
responseError: (rejection) => {
// check if user is logged in
var loggedUserInfo = localStorageService.get<models.LoggedUserInfoModel>('Auth');
if ((rejection.status === 401) && (loggedUserInfo)) {
// if so, then the user must login againd
localStorageService.remove('Auth');
$location.path('/home');
console.error(rejection);
}
return $q.reject(rejection);
}
};
}]);
I appreciate your help.
I am only posting this here in case someone faces a similar issue.
Don't mess with the config object!

spring RESTcontroller to accept dataURI

I am running into a issue of using angularjs ng-img-crop and Spring-boot REST web service.I want to upload an image file from ng crop to my backend web service.
I tried writing a spring controller but it failed and I couldnt find a good tutorial for this. help me resolve this basic request.
Thanks !!!
app.js
angular.module('myApp', [
'ngRoute',
'myApp.view1',
'myApp.view2',
'myApp.version',
'ngImgCrop'
])
.controller('Ctrl',['$scope','notify', function($scope,notify) {
$scope.myImage='';
$scope.myCroppedImage='';
var handleFileSelect=function(evt) {
var file=evt.currentTarget.files[0];
var reader = new FileReader();
reader.onload = function (evt) {
$scope.$apply(function($scope){
$scope.myImage=evt.target.result;
});
};
reader.readAsDataURL(file);
};
angular.element(document.querySelector('#fileInput')).on('change',handleFileSelect);
$scope.submit=function() {
notify($scope.myCroppedImage);
};
}]).
factory('notify',['$http', function($http) {
return function(myCroppedImage) {
var name = 'vishnu';
$http.post('http://localhost:8080/imageUpload', myCroppedImage)
.success(function(data, status, headers, config) {
alert("success");
})
.error(function(data, status, headers, config) {
alert("fail");
});
}
}])
controller.java
#RequestMapping(value="/imageUpload",method=RequestMethod.POST)
#ResponseBody
public String imageUpload(#RequestBody MultipartFile data){
return "success";
}
when I run with the following request, I got some exception in the web service.
Remote Address:127.0.0.1:8080
Request URL:http://localhost:8080/imageUpload
Request Method:POST
Status Code:500 Internal Server Error
Request Headersview source
Accept:application/json, text/plain, /
Accept-Encoding:gzip, deflate
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:1850
Content-Type:application/json;charset=UTF-8
Host:localhost:8080
Origin:file://
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36**
Request payload
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADICAYAAACtWK6eAAAFIklEQVR4Xu3VsRHAMAzEsHj/pTOBXbB9pFchyLycz0eAwFXgsCF.......
Response header
Connection:close
Content-Type:application/json;charset=UTF-8
Date:Fri, 24 Apr 2015 12:40:35 GMT
Server:Apache-Coyote/1.1
Transfer-Encoding:chunked
Exception in java
org.springframework.web.multipart.MultipartException: The current request is not a multipart request
First of all your controller should looks like:
public ResponseEntity<Response> fileUpload(#RequestParam("file") MultipartFile file) {
Use #RequestParam instead of #RequestBody, and send the file in a parameter with the same name you're using in the annotation.
Moreover, your request should be sent with type multipart/form-data. For example, a common html for would be:
<form method="POST" enctype="multipart/form-data" action="your url">

Error when calling springRest webservice by an angularJs Client

I'm trying to call a web service implementyed by Spring REST but the server respond with 400 http code bad request.I will expose some informations about that Ihope that someone can help me.
This is my controller method:
#RequestMapping(value = "/addpost", method = RequestMethod.POST,headers = "Accept=application/json")
public #ResponseBody
String addpost(#RequestBody PostDto post, #RequestBody UserDto user) {
postservice.addPost(post, user);
return "post inserted";
}
The manner by that I call the web service:
$scope.addPost = function() {
$scope.addPost = function() {
$http({
method : 'POST',
url : 'http://localhost:8080/wall/addpost',
data : ({
post : $scope.postt,
user : $scope.userr
}),
}).success(function(data, status, headers, config) {
// $scope.persons.push(data);
alert("Success");
$scope.user = "";
$scope.post = "";
}).error(function(data, status, headers, config) {
alert("erreur");
// called asynchronously if an error occurs
// or server returns response with an error status.
});
};
};
the tow objects "userr" and "postt":
$scope.userr = {
userId : 15,
firstName : "foulen",
lastName: "ben foulen"};
$scope.postt = {
Id : "18",
datePost : null,
note: "Mon message"};
The response of the server:
Etat HTTP 400 - Required PostDto parameter 'post' is not present
these are the headers of request and reponse:
Remote Address:127.0.0.1:8080
Request URL:http://localhost:8080/wall/addpost
Request Method:POST
Status Code:400 Mauvaise Requête
Request Headersview source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip, deflate
Accept-Language:fr-FR,fr;q=0.8,en-US;q=0.6,en;q=0.4
Connection:keep-alive
Content-Length:125
Content-Type:application/json;charset=UTF-8
Host:localhost:8080
Origin:http://localhost:8080
Referer:http://localhost:8080/wall/view/test.html
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.115 Safari/537.36
Request Payloadview source
{post: {idpost: 18, datePost: null, note: "Mon message"},…}
post: {idpost: 18, datePost: null, note: "Mon message"}
datePost: null
idpost: 18
note: "Mon message"
user: {userId: 15, firstName: "foulen", lastName: "ben foulen"}
firstName: "foulen"
lastName: "ben foulen"
userId: 15
Response Headersview source
Connection:close
Content-Length:983
Content-Type:text/html;charset=utf-8
Date:Fri, 27 Feb 2015 11:16:49 GMT
Server:Apache-Coyote/1.1
You cannot use two #RequestBody as it can bind to a single object only (the body can be consumed only once).the much easier way would be to introduce a wrapper Object and change your signature.
The parameters whichever you are passing , are they getting passed to the controller ? I mean to the url you mentioned in the angular controller
'http://localhost:8080/wall/addpost'.
your Angular codes seems good. I think that the problem is on the side of the server codes. The request parameter #RequestParam PostDto post should have a value to indicate its name, like this : #RequestParam PostDto("post") post. According to spring doc, this value by default is "".
To complete, maybe you should use a more normal way of sending request of Angular. I mean to use the json object for the parameters, but not the html form. Because you have already your models of user and post.
Hope help.
EDIT :
Can you modify your angular codes, to send the parameter by json object.
$http({
method : 'POST',
url : 'http://localhost:8080/wall/addpost',
data : ({
post : $scope.postt,
user : $scope.userr
})
}).success(function(data, status, headers, config) {
// $scope.persons.push(data);
alert("Success");
$scope.user = "";
$scope.post = "";
}).error(function(data, status, headers, config) {
alert("erreur");
// called asynchronously if an error occurs
// or server returns response with an error status.
});
};
And delete the header in your java codes :
#RequestMapping(value = "/addpost", method = RequestMethod.POST)
public #ResponseBody
String addpost(#RequestParam(value="post") PostDto post, #RequestParam(value="user") UserDto user) {
postservice.addPost(post, user);
return "post inserted";
}
EDIT :
model:
$scope.postInfo= {
userId : 15,
firstName : "foulen",
lastName: "ben foulen",
postId : "18",
datePost : null,
postnote: "Mon message"
};
AJAX:
$http({
method : 'POST',
url : 'http://localhost:8080/wall/addpost',
data : ({
post : $scope.postInfo
}).// your other codes
})
JAVA :
#RequestMapping(value = "/addpost", method = RequestMethod.POST)
public #ResponseBody String addpost(#RequestBody PostInfoDto post) {
// codes...
}

Resources