just wanted to ask on how to deal with https + cross-domain url using $http?
I've used $.ajax to solve my problem, but the reason why I wanted to use $http more is because I have an $http interceptor since using $.ajax takes a lot more line of codes rather than having an interceptor to automate some process.
I've read similar posts [link1, link2, link3] but neither of them have solved my problem.
I have an attached screenshot of my console, I hope it makes sense:
.
The weird thing is the OPTION Method being used by $http which I have set it to POST
Here's my code snapshot:
$http({
method: 'POST',
url: '/HearingCentre',
data: {
Type: ['P', 'V']
},
success: function (res) {
console.log(res);
d.resolve(res);
},
error: function (res) {
console.log(res);
d.reject(res);
}
});
NOTE: I'm using an $http interceptor here so basically the URL will be appended with the base API URL
$.ajax version
$.ajax({
method: 'POST',
crossDomain: true,
url: 'https://ahtstest.hearing.com.au/services/api/HearingCentre',
data: {
Type: ['P', 'V']
},
success: function (res) {
console.log(res);
},
error: function (res) {
console.log(res);
}
});
Do anyone have a solution for this?
var userApp = angular.module('userApp', []);
userApp.controller('UserController', function ($scope,$http) {
//server call with angular
$scope.makeServerCall = function() {
var url = '/root/jsp/catalog/xml/getJsp.jsp?PatientId=9175;
$http({
crossDomain: true,
xhrFields: {withCredentials: false},
headers: {'Accept': 'application/json','Content-Type': 'application/json'},
method: 'GET',
url: url
}).then(function(response) {
console.log("Success: "+JSON.stringify(response));
},function(response) {
console.log("Error: "+JSON.stringify(response));
});
};
}
And make sure that at your server side you can accessible to cross domain reuqest. Lets say I am using Spring MVC so I have added one filter and configure cross domain request to allow as follow. If you using any other language lets say PHP, then you have to set response header.you can search for the same.
My Server filter Spring mvc
#Component
public class EcwCORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With,isAjaxRequest");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {
}
public void destroy() {
}
}
Related
I have a very simple self-hosted WCF application initialized this way:
Host = new WebServiceHost(this, new Uri(serviceAddress));
var binding = new WebHttpBinding();
binding.ReceiveTimeout = TimeSpan.MaxValue;
binding.MaxReceivedMessageSize = int.MaxValue;
binding.CrossDomainScriptAccessEnabled = true; // TODO: Remove this?
var endpoint = Host.AddServiceEndpoint(typeof(HttpService), binding, "");
Host.Open();
My HttpService class has this method:
[OperationContract, WebInvoke(Method = "*")]
public string Evaluate(string query)
{
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Origin", "*");
if (WebOperationContext.Current.IncomingRequest.Method == "OPTIONS")
{
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Methods", "POST, PUT, DELETE");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Allow-Headers", "Content-Type, Accept, X-Requested-With");
WebOperationContext.Current.OutgoingResponse.Headers.Add("Access-Control-Max-Age", "1728000");
return "";
}
else
{
try
{
return "12345";
}
catch (ProcessNotFoundException ex)
{
throw new WebFaultException<string>(ex.Message, System.Net.HttpStatusCode.NotFound);
}
catch (Exception ex)
{
throw new WebFaultException<string>(ex.Message, System.Net.HttpStatusCode.InternalServerError);
}
}
}
I added the CORS stuff above so that anyone can use this API from any website using JavaScript. And I'm trying to run some POST requests using fetch because once it works, I'll pass large amounts of data so a GET method won't work. Doing the following from JavaScript works OK:
fetch('http://localhost:8001/HeliumScraperService/Evaluate', { method: 'POST', headers: { "Content-Type": 'application/json' }, body: '1232'});
When I do that, my Evaluate method is called first with OPTIONS and then with POST, and an XML string is returned with no errors. The following also works (note the quotes inside the body):
fetch('http://localhost:8001/HeliumScraperService/Evaluate', { method: 'POST', headers: { "Content-Type": 'application/json' }, body: '"hello world"'});
Since both are valid JSON, I though any JSON string would work, so I did this but I got a 400 Bad Request error:
fetch('http://localhost:8001/HeliumScraperService/Evaluate', { method: 'POST', headers: { "Content-Type": 'application/json' }, body: '[10]'});
I thought maybe it wants a JSON that it can convert to my method arguments, but this also doesn't work (gives me a 400 error):
fetch('http://localhost:8001/HeliumScraperService/Evaluate', { method: 'POST', headers: { "Content-Type": 'application/json' }, body: JSON.stringify({ query: "hey" })})
So it can take numbers and strings but nothing else, and I have no idea why. I tried using all these other attribute combinations and got the exact same results:
[OperationContract, WebInvoke(Method = "*", BodyStyle = WebMessageBodyStyle.Bare, RequestFormat = WebMessageFormat.Json)]
[OperationContract, WebInvoke(Method = "*", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json)]
[OperationContract, WebInvoke(Method = "*", BodyStyle = WebMessageBodyStyle.Bare)]
[OperationContract, WebInvoke(Method = "*", BodyStyle = WebMessageBodyStyle.Wrapped)]
I just want to be able to send any string, without something looking into it and deciding whether it's good or bad, while also being able to do the CORS thing above. Is there a way to do this?
I found a workaround but I'm still not sure why it was letting me pass numbers and strings but not arrays, so if someone comes up with an actual explanation I'll be happy to accept that as an answer. My solution was to take a Stream instead of a string in my Evaluate method, and then read the stream like:
using (var memoryStream = new MemoryStream())
{
query.CopyTo(memoryStream);
var array = memoryStream.ToArray();
var lole = Encoding.UTF8.GetString(array);
}
I think the idea is that, since I'm doing the CORS thing and the browser sends an empty body when sending an OPTIONS request, WCF can't handle that as JSON so I have to handle everything myself and the way to do that is by taking a war Stream. Still no idea why it was letting me send numbers and strings (and booleans too BTW) but no arrays (or objects).
At first, the following definition only supports to accept the parameters by using request body, instead of the URL Params.
[OperationContract, WebInvoke(Method = "*")]
public string Evaluate(string query)
Moreover, the body style of the parameters is bare by default.
BodyStyle =WebMessageBodyStyle.Bare
It means that the server accepts the string without wrapping the name of the parameter.
body: '1232'
body: '"hello world"'
When we manually switch the value to BodyStyle=WebMessageBodyStyle.Wrapped, the server will accept the below form. Basically, your attempts are correct. There is just a small problem here.
{"value":"abcd"}
Here is my example, wish it is helpful to you.
Server contract.
[OperationContract]
[WebInvoke(Method ="*",BodyStyle =WebMessageBodyStyle.Wrapped,ResponseFormat =WebMessageFormat.Json)]
string GetData(string value);
JS
<script>
var para1 = { "value": "abcdefg" };
$.ajax({
type: "POST",
url: "http://localhost:8864/Service1.svc/getdata",
data: JSON.stringify(para1),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: OnSuccessCall,
error: OnErrorCall
});
function OnSuccessCall(response) {
console.log(response);
}
function OnErrorCall(response) {
console.log(response.status + " " + response.statusText);
}
</script>
About handing the CORS issue, I add an extra global.asax file.
protected void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
{
HttpContext.Current.Response.AddHeader("Cache-Control", "no-cache");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With,Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
Here is a related document.
https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.web.webmessagebodystyle?view=netframework-4.8
Feel free to let me know if there is anything I can help with.
I am using jquery to make an API call to an Entity Framework API Controller and I am trying to call the Put Method:
[ResponseType(typeof(void))]
public IHttpActionResult PutProfileIDClass(int id, ProfileIDClass profileIDClass)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != profileIDClass.id)
{
return BadRequest();
}
db.Entry(profileIDClass).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch (DbUpdateConcurrencyException)
{
if (!ProfileIDClassExists(id))
{
return NotFound();
}
else
{
throw;
}
}
return StatusCode(HttpStatusCode.NoContent);
}
But when I make the API call via jQuery I get this error: 405 (Method Not Allowed)
What Am I doing wrong?
Here is my API call
var data = {
id: result.data[0].id,
profileID: result.data[0].profileID,
taken: 'true'
};
var json = JSON.stringify(data);
$.ajax({
url: '/api/ProfileIDAPI?id=' + result.data[0].id,
type: 'PUT',
contentType: "application/json; charset=utf-8",
data: json,
success: function (results) {
}
});
If you want to do a PUT request you should use the method: 'PUT' as part of your $.ajax call:
$.ajax({
url: '/api/ProfileIDAPI?id=' + result.data[0].id,
method: 'PUT',
contentType: "application/json; charset=utf-8",
data: json,
success: function (results) {
}
});
Do you have it installed on IIS? In that case, you have to configure it to handle your "PUT" request.
Right click on your website in the sidebar and go to properties.
Go to the "Home Directory" Tab
In the "applications settings", click on the "configuration" button
In the "Applications configuration" Window, there should be a Mappings Tab
Simply choose which file extensions you want to have mapped (in my case i wanted ASP to map GET, PUT, POST & DELETE), comma delimited. And thats it, not even a restart required.
Hope this helps
I'm trying to make an angularjs $http.get request with parameters but it's not working due to syntaxt may be. Can you please
confirm what i'm doing wrong , maybe syntax is wrong in angularjs call or in java api method
$http.get(document.requestPathPrefix + "/home/my-api",
$scope.requestParametersObject
).then(
function(response) {
$scope.output = response.data;
},
function(response) {
$scope.retrieveErrorMssg = "Failed to retrieve required data.";
});
my parameters are like in this image
parameter object for api call
And in java api call like this
#RequestMapping(value = "/my-api", method = RequestMethod.GET)
public ResponseEntity<Collection<MyObjectResponse>> getMyObjResponse(#RequestBody final MyObjectRequest request)
{
Map<Integer,MyObjectResponse> oResponse = new HashMap<>();
try {
//Manipulation and db calls
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return new ResponseEntity<Collection<MyObjectResponse>>(oResponse.values(), HttpStatus.OK);
}
try ,
$http({
url: '/home/my-api',
method: "GET",
headers: {
'Content-type': 'application/json'
},
data: JSON.stringify(request)
}).success(function(data, status, headers, config) {
}).error(function(data, status, headers, config) {
return null;
});
If you are worried about syntax, take a look at this simple example and modify it to your need.
In JS, your http.get call should contain the URL and its parameters if any,
$http.get('getUserInfo',
{
params : {
'userEmail' : 'userEmail'
}
}).then(function(response) {
console.log(response);
});
If you are passing a parameter to the API call, ensure your Java controller or the service has the parameter defined to receive the same. Ideally the parameters should match between the call and the provider
For example, for the above API call, the spring controller should like below,
#RequestMapping(value = "/getUserInfo", method = RequestMethod.GET)
public #ResponseBody User getUserInfo(
#RequestParam("userEmail") String userEmail) {
// Do Something
}
I want to access POST method from my server, but when I logged the response, it's always return status=0, anyone can help me or give me an advise?
note: I've tried my method in Postman and it's works anyway
This is my contorller
nameApp.controller('loginCtrl', ['$scope','$location','Flash','$sessionStorage', '$cookieStore','$http',function (scope,location,Flash,sessionStorage,cookieStore,http) {
scope.nim='';
scope.pass='';
if(cookieStore.get('current')!=null){
location.path('/homepage')
}
scope.login = function() {
if((scope.nim=='')){
Flash.create('danger', 'Invalid Username / Password', 'custom-class');
}else{
http.post('http://localhost:8084/iec3/rest/users/login',{'username':'admin','password':'bukanadmin'},{headers: {'Content-Type': 'application/json'}
}).then(function successCallback(response) {
console.log("GREAT");
}, function errorCallback(response) {
console.log(response)
});
}
}
}]);
This is login method from my controller
#Path("/login")
#POST
#Consumes(value = MediaType.APPLICATION_JSON)
#Produces(value = MediaType.APPLICATION_JSON)
public Response login(User user) {
UserDao ud = new UserDao();
User dariDB = ud.login(user.getUsername(), user.getPassword());
dariDB.setPassword("");
return Response.ok(dariDB)
.header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
.header("Access-Control-Allow-Credentials", "true")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD")
.header("Access-Control-Max-Age", "1209600")
.build();
}
This Is the error when i try to logged the response
Object {data:null, status:0, headers:dd/<(), config:Object, statusText:""}
You need to verify if your request is reaching to the server. Is your login method is getting called? If you are on same host, there is no need to pass complete url, you can directly call your api via its path.
As for a newbie, I would recommend you to avoid $http shortcut methods. For better understanding and readability, you should use $http like
$http({
method: 'POST',
url: 'http://localhost:8084/iec3/rest/users/login',
data: {
username:'admin',
password:'bukanadmin'
},
headers: {
'Content-Type': 'application/json'
}
}).then(function successCallback(response) {
console.log("GREAT");
}, function errorCallback(response) {
console.log(response)
});
Your request from ajax does not seem to hit your controller method, status 0 is usually returned when the request is cancelled. Check the #path value in controller method and the http://localhost:8084/iec3/rest/users/login mapping.
For more details about status 0
http://www.w3.org/TR/XMLHttpRequest/#the-status-attribute
I'm sorry to ask this question again, but I didn't find a fitting answer to my problem.
I try to build the following:
I want to connect to a WCF-Webservice with a standard Webpage. Both website and web service are hosted in an IIS on the same machine.
I enabled cross-domain to the web.config:
<webHttpBinding>
<binding name="webHttpBindingWithJSONP" crossDomainScriptAccessEnabled="true" />
</webHttpBinding>
And my AJAX request:
$.ajax({
type: "POST",
url: config.endpoints.db.production + "AddData/",
data: JSON.stringify(data),
contentType: "application/json",
dataType: "json",
crossDomain: true,
// processData: true,
success: function(data, status, jqXHR) {
// alert("success..." + data);
// loadingVisible(false);
// loadingFinished = true;
},
error: function(xhr) {
alert("failure..." + xhr.responseText);
// loadingFinished = true;
// loadingVisible(false);
}
});
After firing the request I got an "Access denied"-Error in the visual studio from jquery.
After searching in the web I found out that this is a very common cross-domain problem, but I didn't find a solution. I tried to set "crossDomain: true" in the ajax-request, tried to use jsonp (which worked for my GET-requests) but nothing helped.
Is there a proper way to solve this? I read that this problem might be solved with an ajax authentication. Is that correct and how can I achieve that?
To solve the problem do the following
Create a Global.asax and add following to enable Ajax cross-domain POST
public void Application_BeginRequest(object sender, EventArgs e)
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, POST,OPTIONS");
if ((HttpContext.Current.Request.HttpMethod == "OPTIONS"))
{
HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept");
HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
HttpContext.Current.Response.End();
}
}
}
At your service set
[AspNetCompatibilityRequirements(RequirementsMode =
AspNetCompatibilityRequirementsMode.Allowed)]
public class YourserviceName : YourserviceNameInterface