I am creating an app which uses some node.js scripts for server scripting mainly because node.js has Firebase support, but for some reason I am unable to send any params with my request (both GET and POST).
My android code is as follows
private void sendData(final String name){
StringRequest sr = new StringRequest(Request.Method.GET, URL, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Toast.makeText(getApplicationContext(),response.toString()+" returned from node.js server",Toast.LENGTH_SHORT).show();
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(),error.toString()+"The Server returned error",Toast.LENGTH_SHORT).show();
}
}){
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
HashMap<String,String> map = new HashMap<>();
map.put("test",name);
return map;
}
};
RequestQueue r = Volley.newRequestQueue(getApplicationContext());
r.add(sr);
}
The corresponding node.js script is as follows
app.get('/hello', function(request, response){
var outputJson = request.params.test;
response.send(JSON.stringify(outputJson));
console.log(outputJson);
})
The console always logs undefined for some reason. Following suggestions from this post I also tried including the data in the body of the request and get the data from the request in the node.js via request.body.test.
I would like to know what is going wrong and most importantly I would also like to know how to recieve and process POST request. I read on some blog that I have to implement a middleware of some kind. Some clarification in that area will also be appreciated.
I have looked at your code and found that there are some flaws in the Android Code.
The HashMap is defined in a getHeaders() function but it should actually be defined in getParams() like this
#Override
public Map<String, String> getParams() throws AuthFailureError {
HashMap<String,String> map = new HashMap<>();
map.put("test",name);
return map;
}
Instead of trying to retrieve the data by request.params try using request.body.
Related
I work on spring boot and angular I made an authentication based on spring security I tested with postman and everything works fine, but when I use angular it does not work after debugging I noticed that request. getParameter("username") return null, the error is probably on the angular request, please can someone help me
#Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
// TODO Auto-generated method stub
String username = request.getParameter("username");
System.out.println(username);
String password = request.getParameter("password");
System.out.println(password);
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(username, password);
return authManager.authenticate(authToken);
}
//req angular
login(params:any) : Observable<any> {
let username=params.username as string
let password=params.password as string
const FORM_URL = {
headers:{
'Content-Type': 'application/json'
}
}
return this.http.post<any>(`${this.adresse+'/login'}`,{
'username':username,
'password':password
}, FORM_URL)}
}
According to the documentation:
Returns the value of a request parameter as a String, or null if the parameter does not exist.
Find out where this parameter should come from. Candidates are the client request, the container and the Sprint Boot framework. Once you know which side is supposed to set it, figure out why it does not.
One answer can be as simple as 'the user has not yet authenticated'. For a more focused response you'd have to share more details.
So, I've the following code
#RequestMapping(value = "/api/store")
#ResponseBody
public ModelMap doSomething(
HttpServletResponse response,
#RequestParam String a,
#RequestParam(defaultValue = "false") final boolean x,
) {
ModelMap model = new ModelMap();
if (x) {
throw new throw new Exception("You already submitted your data!");
}
model.put("a", a);
return model;
}
now the scenario is, that when the user fill out the form and clicks on submit, the request goes through this mapping and it working perfectly, and the x will be assigned to true.
Now the problem: when the user refreshes the page, another POST Method will be sent to this mapping, and hence an error will be shown to the user (because of the if statement).
Now I think, I have to use the PRG Pattern, and redirect the user to GET (from POST), but the examples were mostly using ModelAndView, and since I'm using ModelMap, I'm lost, how to implement it using ModelMap.
This backend API is then connected to some JS Frontend.
I assume, that I have to create two methods, one GET Method and one POST Method, in the GET Method I have to implement the logic and everything and in POST I've to simply redirect to the GET Method.
Update:
I added the following get method:
#GetMapping(value = "/api/store")
public ModelAndView doSomethingGet(
HttpServletResponse response,
#RequestParam final String code,
#RequestParam(defaultValue = "false") final boolean x
) {
return new ModelAndView("redirect:/api/store");
}
and I've also changed the post method to this:
#PostMapping(value = "/api/store")
public ModelMap doSomething(
HttpServletResponse response,
#RequestParam String a,
#RequestParam(defaultValue = "false") final boolean x,
) {
ModelMap model = new ModelMap();
if (x) {
throw new throw new Exception("You already submitted your data!");
}
model.put("a", a);
return model;
}
You're right. You need to create two methods using GET and POST annotations.
#GetMapping(value = "/api/store") - Just return the view
#PostMapping(value = "/api/store") - Implement business logic
Say I have a spring:form binded with MyObject class and on submit I hit this Controller method:
#PostMapping(value = "/saveObject")
public String saveInterest(#ModelAttribute("myObject") MyObject myObject, BindingResult result,
ModelMap model, RedirectAttributes redirectAttrs, HttpServletRequest request, HttpServletResponse response,
HttpSession session) throws Exception {
try {
// MY NEED IS HERE
myService.saveMyObject(myObject);
} catch (Exception e) {
throw new Exception("error when trying to save my object");
}
return "redirect:/dasboard";
}
What I want to achieve is passing myObject to an external application too on submit, by that I mean opening this external application in a new tab with myObject filling a similar spring:form.
Here is what I did so far :
Created a Restful Web Service client that hits an external application controller in which I receive myObject and fill a spring:form with it before returning a ModelAndView.
My question is how can I implement this new tab behavior, am I missing something obvious ?
I am using a WCF (.svc) WebService and it's working perfectly - I can call its methods without problems from Postman, PHP, etc. But, when I try to call it from JavaScript/jQuery using AJAX, there is an obvious problem - I do it from other domain than WS, so it won't let me do it.
It is all about POST methods. But there is a problem even when my page is sending firstly an OPTIONS method:
OPTIONS 'WS ADDRESS' 405 (Method Not Allowed)
XMLHttpRequest cannot load 'WS ADDRESS' Response to preflight request doesn't
pass access control check: No 'Access-Control-Allow-Origin' header is
present on the requested resource. Origin 'MY ADDRESS' is therefore not allowed
access. The response had HTTP status code 405.
There are detailed responses:
Okay, I read about cross-domain and WS's Web.config contains all of it that is necessary (?)
Please let me know what am I doing wrong that I cannot reach my WS from JavaScript, even though it seems to me configured well. But still, it seems not to send these special headers in response... Thanks in advance.
XML HttpRequest allows data to be transferred from a web server to the browser. The browsers, however, prevents CORS by default.
GET request is not going to change anything on the server side (nothing is created/updated/deleted) - it's only going to return some data.
POST/PUT/DELETE requests, however, will process the request and change something on the server side and issue a response to the browser. If the response doesn't have a proper Access-Control-Allow-Origin header, the browser will block the response. But that doesn't matter because by the time the response is issued, the server has already processed the request and made changes, perhaps to a database.
In order to prevent POST/PUT/DELETE request to be processed on server side, browsers will send a preflight request.
A prefligth request is an http request with the method OPTIONS. So before sending the POST request, the browser will send an OPTIONS request with an additional header called Access-Control-Request-Method with the value of POST.
The 405 (Method Not Allowed) error indicates the the server is not configured to accept OPTIONS request.
You can solve this issue either by using a wildcard for your web invoke method similar to this:
[OperationContract]
[WebInvoke(Method = "*", UriTemplate = "/Path", ResponseFormat = WebMessageFormat.Json)]
Or by adding an additional [OperationContract] to your [ServiceContract] that handles OPTIONS request similar to this:
[OperationContract(Name = "OptionsMyFunction")]
[WebInvoke(Method = "OPTIONS", UriTemplate = "/Path", ResponseFormat = WebMessageFormat.Json)]
You can implement .NET IDispatchMessageInspector for this work.
Create a class implementing IDispatchMessageInspector
Create a class implementing Attribute,IEndpointBehavior,IOperationBehavior
Allow only OPTIONS in your class implementing IDispatchMessageInspector
The code will look like this
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Description;
using System.Collections.Generic;
using System.Net;
namespace WapstyPrintService
{
public class MessageInspector : IDispatchMessageInspector
{
private ServiceEndpoint _serviceEndpoint;
Dictionary<string, string> requiredHeaders;
public MessageInspector(ServiceEndpoint serviceEndpoint)
{
_serviceEndpoint = serviceEndpoint;
requiredHeaders = new Dictionary<string, string>();
requiredHeaders.Add("Access-Control-Allow-Origin", "*");
requiredHeaders.Add("Access-Control-Request-Method", "POST,GET,PUT,DELETE,OPTIONS");
requiredHeaders.Add("Access-Control-Allow-Headers", "X-Requested-With,Content-Type");
}
/// <summary>
/// Called when an inbound message been received
/// </summary>
/// <param name="request">The request message.</param>
/// <param name="channel">The incoming channel.</param>
/// <param name="instanceContext">The current service instance.</param>
/// <returns>
/// The object used to correlate stateMsg.
/// This object is passed back in the method.
/// </returns>
public object AfterReceiveRequest(ref Message request,
IClientChannel channel,
InstanceContext instanceContext)
{
var httpRequest = (HttpRequestMessageProperty)request
.Properties[HttpRequestMessageProperty.Name];
return new
{
origin = httpRequest.Headers["Origin"],
handlePreflight = httpRequest.Method.Equals("OPTIONS",
StringComparison.InvariantCultureIgnoreCase)
};
}
/// <summary>
/// Called after the operation has returned but before the reply message
/// is sent.
/// </summary>
/// <param name="reply">The reply message. This value is null if the
/// operation is one way.</param>
/// <param name="correlationState">The correlation object returned from
/// the method.</param>
public void BeforeSendReply(ref Message reply, object correlationState)
{
var state = (dynamic)correlationState;
if (state.handlePreflight)
{
reply = Message.CreateMessage(MessageVersion.None, "PreflightReturn");
var httpResponse = new HttpResponseMessageProperty();
reply.Properties.Add(HttpResponseMessageProperty.Name, httpResponse);
httpResponse.SuppressEntityBody = true;
httpResponse.StatusCode = HttpStatusCode.OK;
}
var httpHeader = reply.Properties["httpResponse"] as HttpResponseMessageProperty;
foreach (var item in requiredHeaders)
{
httpHeader.Headers.Add(item.Key, item.Value);
}
}
}
}
and
using System;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace WapstyPrintService
{
public class BehaviorAttribute : Attribute, IEndpointBehavior,
IOperationBehavior
{
public void Validate(ServiceEndpoint endpoint) { }
public void AddBindingParameters(ServiceEndpoint endpoint,
BindingParameterCollection bindingParameters)
{ }
/// <summary>
/// This service modify or extend the service across an endpoint.
/// </summary>
/// <param name="endpoint">The endpoint that exposes the contract.</param>
/// <param name="endpointDispatcher">The endpoint dispatcher to be
/// modified or extended.</param>
public void ApplyDispatchBehavior(ServiceEndpoint endpoint,
EndpointDispatcher endpointDispatcher)
{
// add inspector which detects cross origin requests
endpointDispatcher.DispatchRuntime.MessageInspectors.Add(
new MessageInspector(endpoint));
}
public void ApplyClientBehavior(ServiceEndpoint endpoint,
ClientRuntime clientRuntime)
{ }
public void Validate(OperationDescription operationDescription) { }
public void ApplyDispatchBehavior(OperationDescription operationDescription,
DispatchOperation dispatchOperation)
{ }
public void ApplyClientBehavior(OperationDescription operationDescription,
ClientOperation clientOperation)
{ }
public void AddBindingParameters(OperationDescription operationDescription,
BindingParameterCollection bindingParameters)
{ }
}
}
Then add your message inspector to service endpoint behavior
ServiceHost host = new ServiceHost(typeof(myService), _baseAddress);
foreach (ServiceEndpoint EP in host.Description.Endpoints)
EP.Behaviors.Add(new BehaviorAttribute());
I am currently trying to develop a simple angular js application.
I am trying to post data from client to web api.
However, I am getting 404 error when I fire post request from angular app.
Below is my post request,
$http.post('/api/LoadApi/', jsonData).then(function (result) {
console.log(result.data);
})
.catch(function (error) {
});
where jsonData is a valid json data.
My web api code is this,
public class LoadApiController : ApiController
{
[HttpPost]
public HttpResponseMessage LoadData(object dataToLoad)
{
var response = Request.CreateResponse(HttpStatusCode.Created);
return response;
}
}
My web api route config is this,
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{dataToLoad}"
);
However, when I run the code, it throws an error
Server Error in '/' Application.
The resource cannot be found.
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /api/LoadApi/
Can anyone point what is the problem with the above code?
It says there is some problem with url. The url generated is http://localhost:14154/api/LoadApi/ which looks correct.
The issue is with your route definition and how you are trying to send data to your controller method. I would recommend using attribute based routing. In your Web API controller do this:
[RoutePrefix("api/LoadApi")]
public class LoadApiController : ApiController
{
[HttpPost]
[Route("loadData")]
public HttpResponseMessage LoadData(object dataToLoad)
{
var response = Request.CreateResponse(HttpStatusCode.Created);
return response;
}
}
Change the Application_Start() method in Global.asax.cs to this:
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
Make sure WebApiConfig.cs in App_Start has a Register() method like this:
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
}
And finally change your $http.post call to this:
$http.post('/api/LoadApi/loadData', jsonData).then([...]);