HTTP Status 405 - Request method 'POST' not supported - jQuery.post() - spring-mvc

Update: See here for solution
Using Spring MVC 4.
Here's my JavaScript code that makes the POST request:
$("input.toggleCourse").change(function(e){
var d = {
classID: classID,
courseID: courseID
};
$.post(
"<c:url value="/class/addCourse" />",
JSON.stringify(d))
.done(function(data){
alert("ok");
});
});
(Tried with and without JSON.stringify, tried full $.ajax instead of $.post)
Here's my controller
#RequestMapping(value = "/class/addCourse", method = RequestMethod.POST)
public #ResponseBody String addCourse(#RequestBody final CourseInClass cic) {
StringBuilder sb = new StringBuilder();
try{
Class c = classServ.findOne(cic.ClassID);
c.Courses.add(courseServ.findOne(cic.CourseID));
sb.append("{success:true}");
} catch (Exception e){
sb.append("{error:\"").append(e.getMessage()).append("\"}");
}
return sb.toString();
}
I checked the network log that it sends the correct headers to the correct url. Post requests work for normal forms, but not for this ajax call.
Thanks.

How do you think (String classID, String courseID) will be detected by Spring. i.e. how will the json object be mapped to java object.
If you want to use auto binding you can use jackson-mapper-asl. Take a look at this page
If you don't want to use it you can use #PathVariable,
change method signatures to public #ResponseBody String addCourse(#PathVariable String classID, #PathVariable String courseID) {..}
and then hit http://localhost:8080/<appname>/class/addCourse/<classID>/<courseID>

Related

Can I disable model binding and use the raw request body in an action in dotnet core?

I want to setup an endpoint for testing webhooks from third parties. Their documentation is uniformly poor and there is no way ahead of time to tell exactly what I will be getting. What I've done is setup an ApiController that will just take a request and add a row to a table with what they are sending. This lets me at least verify they are calling the webhook, and to see the data so I can program to it.
// ANY api/webook/*
[Route("{*path}")]
public ActionResult Any(string path)
{
string method = Request.Method;
string name = "path";
string apiUrl = Request.Path;
string apiQuery = Request.QueryString.ToString();
string apiHeaders = JsonConvert.SerializeObject(Request.Headers);
string apiBody = null;
using (StreamReader reader = new StreamReader(Request.Body))
{
apiBody = reader.ReadToEnd();
}
Add(method, name, apiUrl, apiQuery, apiHeaders, apiBody);
return new JsonResult(new { }, JsonSettings.Default);
}
This works great, except for this new webhook I am usign that posts as form data so some middleware is reading the body and it ends up null in my code. Is there any way to disable the model processing so I can get at the request body?
You could actually use model binding to your advantage and skip all that stream reading, using the FromBody attribute. Try this:
[Route("{*path}")]
[HttpPost]
public ActionResult Any(string path, [FromBody] string apiBody)

Can Spring MVC controller set the URL to be shown in browser?

We have a Spring MVC Controller method which servers the url pattern /hello/{userName} .
#RequestMapping("/hello/{userName}")
public ModelAndView helloWorld(#PathVariable("userName") String productId) {
String message = "HELLO"+userName;
return new ModelAndView("hellopage", "message", message);
}
Here when we request /hello/Tom ,hellopage.html will be servered with URL in the browser http://localhost:8080/myApp/hello/Tom
We would need the URL to be http://localhost:8080/myApp/Tom .Is there any way I can set the URL to be shown in the browser when returning from the controller.
Sure you can do that using redirect. Write two controllers:
#RequestMapping("/hello/{userName}")
public string helloWorld(#PathVariable("userName") String userName, Model model) {
String message = "HELLO" + userName;
model.addAttribute("message", message);
return "redirect:" + userName;
}
#RequestMapping("/{userName}")
public ModelAndView userHello((#ModelAttribute("message") String message)) {
return new ModelAndView("hellopage", "message", message);
}
I think you could also use tuckey url-rewrite for this: http://tuckey.org/urlrewrite/
This allows Apache mod_rewrite functionality in Tomcat through the use of a filter, and you wouldn't have to write two controllers for everything.

How to set content type dynamically in a Spring MVC controller (depending on presence of request param)?

I have a REST API that until now always returned JSONP (JSON data wrapped in whatever function call client wanted):
static final String JAVASCRIPT = "application/javascript;charset=UTF-8";
#RequestMapping(value = "/matches", produces = JAVASCRIPT)
#ResponseBody
public String matches(#RequestParam String callback) {
String json = jsonService.getCachedJson("/matches");
return toJsonp(callback, json);
}
Now, things have changed so that I need to return either JSON or JSONP: if client provides a callback function name, we return JSONP and otherwise pure JSON.
With regards to content type, I'd like to be as correct as possible and use application/json for JSON and application/javascript for JSONP.
So, something like this:
#RequestMapping(value = "/matches")
#ResponseBody
public String matches(#RequestParam(required = false) String callback) {
String json = jsonService.getCachedJson("/matches");
// TODO: if callback == null, set content type to "application/json",
// otherwise to "application/javascript"
return jsonOrJsonp(callback, json);
}
String jsonOrJsonp(String callback, String json) {
return Strings.isNullOrEmpty(callback) ? json : toJsonP(callback, json);
}
Looks like I can no longer use produces attribute of #RequestMapping. What's the simplest way to set content type with Spring MVC in the scenario above?
I'd like to avoid defining HttpMessageConverters (or other Spring hassle) or changing the method return type, if at all possible! And obviously I wouldn't like duplicated method declarations where produces value is the only significant difference. What I'm looking for is minimal changes to the above code.
Latest Spring (3.2.3).
Have you tried just using two request handler methods?
#RequestMapping(value = "/matches", produces = JAVASCRIPT, params="callback")
#ResponseBody
public String Jsonp(#RequestParam String callback) {
return toJsonp(callback, jsonService.getCachedJson("/matches"));
}
#RequestMapping(value = "/matches", produces = JSON)
#ResponseBody
public String json() {
return toJson(jsonService.getCachedJson("/matches"));
}
The first method with the params parameter will only be mapped to requests where the callback param is present.

How to get Json Post Values with asp.net webapi

i'm making a request do a asp.net webapi Post Method, and i'm not beeing able to get a request variable.
Request
jQuery.ajax({ url: sURL, type: 'POST', data: {var1:"mytext"}, async: false, dataType: 'json', contentType: 'application/x-www-form-urlencoded; charset=UTF-8' })
.done(function (data) {
...
});
WEB API Fnx
[AcceptVerbs("POST")]
[ActionName("myActionName")]
public void DoSomeStuff([FromBody]dynamic value)
{
//first way
var x = value.var1;
//Second way
var y = Request("var1");
}
i Cannot obtain the var1 content in both ways... (unless i create a class for that)
how should i do that?
First way:
public void Post([FromBody]dynamic value)
{
var x = value.var1.Value; // JToken
}
Note that value.Property actually returns a JToken instance so to get it's value you need to call value.Property.Value.
Second way:
public async Task Post()
{
dynamic obj = await Request.Content.ReadAsAsync<JObject>();
var y = obj.var1;
}
Both of the above work using Fiddler. If the first option isn't working for you, try setting the content type to application/json to ensure that the JsonMediaTypeFormatter is used to deserialize the content.
After banging my head around for a while on this and trying many different things I ended up putting some breakpoints on the API server and found the key value pairs stuffed down in the request. After I knew where they were, it was easy to access them. However, I have only found this method to work with WebClient.UploadString. However, it does work easily enough and allows you to load up as many parameters as you like and very easily access them server side. Note that I am targeting .net 4.5.
CLIENT SIDE
// Client request to POST the parameters and capture the response
public string webClientPostQuery(string user, string pass, string controller)
{
string response = "";
string parameters = "u=" + user + "&p=" + pass; // Add all parameters here.
// POST parameters could also easily be passed as a string through the method.
Uri uri = new Uri("http://localhost:50000/api/" + controller);
// This was written to work for many authorized controllers.
using (WebClient wc = new WebClient())
{
try
{
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
response = wc.UploadString(uri, login);
}
catch (WebException myexp)
{
// Do something with this exception.
// I wrote a specific error handler that runs on the response elsewhere so,
// I just swallow it, not best practice, but I didn't think of a better way
}
}
return response;
}
SERVER SIDE
// In the Controller method which handles the POST request, call this helper:
string someKeyValue = getFormKeyValue("someKey");
// This value can now be used anywhere in the Controller.
// Do note that it could be blank or whitespace.
// This method just gets the first value that matches the key.
// Most key's you are sending only have one value. This checks that assumption.
// More logic could be added to deal with multiple values easily enough.
public string getFormKeyValue(string key)
{
string[] values;
string value = "";
try
{
values = HttpContext.Current.Request.Form.GetValues(key);
if (values.Length >= 1)
value = values[0];
}
catch (Exception exp) { /* do something with this */ }
return value;
}
For more info on how to handle multi-value Request.Form Key/Value pairs, see:
http://msdn.microsoft.com/en-us/library/6c3yckfw(v=vs.110).aspx
I searched all morning to find an answer that depicted both client and server code, then finally figured it out.
Brief intro - The UI is an MVC 4.5 project that implements a standard view. The server side is an MVC 4.5 WebApi. The objective was to POST the model as JSON and subsequently update a database. It was my responsibility to code both the UI and backend. Below is the code. This worked for me.
Model
public class Team
{
public int Ident { get; set; }
public string Tricode { get; set; }
public string TeamName { get; set; }
public string DisplayName { get; set; }
public string Division { get; set; }
public string LogoPath { get; set; }
}
Client Side (UI Controller)
private string UpdateTeam(Team team)
{
dynamic json = JsonConvert.SerializeObject(team);
string uri = #"http://localhost/MyWebApi/api/PlayerChart/PostUpdateTeam";
try
{
WebRequest request = WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/json; charset=utf-8";
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
WebResponse response = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
}
catch (Exception e)
{
msg = e.Message;
}
}
Server Side (WebApi Controller)
[Route("api/PlayerChart/PostUpdateTeam")]
[HttpPost]
public string PostUpdateTeam(HttpRequestMessage context)
{
var contentResult = context.Content.ReadAsStringAsync();
string result = contentResult.Result;
Team team = JsonConvert.DeserializeObject<Team>(result);
//(proceed and update database)
}
WebApiConfig (route)
config.Routes.MapHttpRoute(
name: "PostUpdateTeam",
routeTemplate: "api/PlayerChart/PostUpdateTeam/{context}",
defaults: new { context = RouteParameter.Optional }
);
Try this.
public string Post(FormDataCollection form) {
string par1 = form.Get("par1");
// ...
}
try using following way
[AcceptVerbs("POST")]
[ActionName("myActionName")]
public static void DoSomeStuff(var value)
{
//first way
var x = value;
}

Spring MVC and Prototype JavaScript

I am trying to call a Spring MVC controller through an ajax call from JavaScript method.The javascript method is using Prototype library to make the ajax call.The controller throws JSP as output.
I am able to hit the controller as i can see in the log messages however the response seems to get lost.What could be the issue.Here is the code....
function submitNewAjxCall() {
alert('test');
new Ajax.Request('SimpleApp/home.htm',
{
method:'post',
parameters: $('formId').serialize(true),
onComplete: showresult
});
}
function showresult(resultdata) {
alert(resultdata.responseText); ****//this method is not called.....****
}
home.htm point to this controller
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
System.out.println("HomeController : " + ++i);
return new ModelAndView("home");
} --- this throws home.jsp
Thanks for your help.
Check with Firebug (Net tab) if you get the Ajax response and and see what its content is.
Maybe it makes sense to not return the whole HTML page but a JavaScript specific JSON object that's telling something about what the controller just did. Maybe add a ajax GET property to your controller where you just output plain JSON to the Response Body instead of returning the ModelAndView. Try to use onSucess in Prototype. Maybe that might work then
function submitNewAjxCall()
{
new Ajax.Request('SimpleApp/home.htm?ajax=true',
{
method: 'post',
parameters: $('formId').serialize(true),
onComplete: function(transport)
{
alert(transport.responseText);
}
});
}
Edit: To write JSON directly (e.g. using Flexjson as the serializer) you can use this in your (annotated) Spring controller:
#RequestMapping(value = "/dosomething.do", method = RequestMethod.GET, params = "ajax=true")
public void getByName(
#RequestParam(value = "name", required = true) String name,
HttpServletResponse response
)
{
response.setContentType("application/json");
try
{
OutputStreamWriter os = new OutputStreamWriter(response.getOutputStream());
List<DomainObjects> result = this.domainObjectService.getByName(name);
String data = new JSONSerializer().serialize(result);
os.write(data);
os.flush();
os.close();
} catch (IOException e)
{
log.fatal(e);
}
}

Resources