I work on a website (called websiteA) who wants some bespoke data to be stored.
As such, we realised the best way is to have another website (websiteB) which would handle this. So, when a user visits websiteA, it calls websiteB and passes some information across.
The code I used to use (which I recieved form this post How to get json from MVC4 C# with no javascript and no Ajax) is
using (var client = new HttpClient())
{
var responseString = client.GetStringAsync("http://www.example.com/recepticle.aspx?withQueryString=true"); //I don't actually use the responseString
}
The point is though, when I asked that question, a comment was left (now deleted) explaining I should use WebApi instead. So I did... And this is where it is going wrong.
I have created the Web Api 2 project, and I post using Ajax and it works in my local host. I've now deployed to my test environment and realised I can't achieve what I want because of cross domain origin issues.
Further reading suggests I can't use json, but must use jsonp but, jsonp only works with get where as I need post (How to use type: "POST" in jsonp ajax call).
I guess I could use 'get' and just ignore the response but this feels like a hack...
Sorry for asking 2 questions but I think they're very much related.
Question 1 is: if the jsonp requires a callback, is it actually using a get but the get is being called from the target machine (websiteB)? So, instead of posting from websiteA to websiteB, does jsonp actually mean websiteA passes the callback to websiteB, and websiteB actually invokes the callback (meaning essentially, websiteB is calling websiteA)?
Question 2 (the main question) : How do I post information from websiteA to websiteB using javascript/ajax/jquery. Or will I have to enable CORS on websiteB server and then use a ajax's post and json?
Dave Ward has the perfect article on how to do this on his blog:
http://encosia.com/using-cors-to-access-asp-net-services-across-domains/
In short, place the following in your webconfig.
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
</httpProtocol>
</system.webServer>
First, I want to introduce these names to make the explanation a little less confusing.
WebsiteA = App = Web-Client application
WebsiteB = API = Data provider
Question 1:
if the jsonp requires a callback, is it actually using a get but the get is being called from the target machine (websiteB)?
So, instead of posting from websiteA to websiteB, does jsonp actually mean websiteA passes the callback to websiteB, and websiteB actually invokes the callback (meaning essentially, websiteB is calling websiteA)?
Answer to question 1:
The API does not invoke any JavaScript closures (callback) from the App. The callback in the JSONP communication technique is the name of the (global) function in the context of the client, specified by the App itself. This callback is invoked by the App, after the payload is received from the remote service. It is by convention alone that the App can specify the name of the padding function. Meaning that the service is kind enough to let you decide which function you want to call after data is received.
The service outputs this function as "plain text" because <script> expects to find valid JavaScript under src=. The response can not contain a valid JSON object alone because <script> is not responsible for assigning variables, but for running actual scripts and if the remote service would respond with var weatherData = { ... }, then weatherData would be accessible in the context of the client. I'm not sure why the padding-function approach is considered as more favorable. Probably because it is easier to parse safely.
App.html
(incorrect syntax for the sake of brevity)
<html>
<head>
<title> Weather App
<script src=weater-station.com/next-week/?callback=parseRemoteWeatherData />
<script>
var app = {
main: function() { /* init views, etc */ },
receiveWeatherData: funciton(maybeJson) {
// validate payload in maybeJson
}
}
// expose the callback
window.parseRemoteWeatherData = app.receiveWeatherData
API response to /next-week/?callback=parseRemoteWeatherData
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2.0.61
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/javascript
parseRemoteWeatherData('any-text, but JSON by convention');
So the simple explanations is:
The client specifies a function name and gets a script that calls this function with the data as the first parameter.
Question 2:
How do I post information from websiteA to websiteB using javascript/ajax/jquery. Or will I have to enable CORS on websiteB server and then use a ajax's post and json?
Answer to question 2
As per the CORS (and HTTP 1.1) specification you can issue a POST method to any service, provided that:
Content-Type header contains one of application/x-www-form-urlencoded, multipart/form-data, or text/plain.
The request does not contain any custom headers
If you want to post Content-Type: application/json, then CORS must be enabled on both the server and the client. The server must handle OPTION negotiation call (Preflighted requests) correctly and respond with the header Access-Control-Allow-Origin: * (or the domain name of the client) while the client must send the header Origin: hostname.tld.
Relevant specifications
https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
https://developer.mozilla.org/en-US/docs/Web/HTTP/Server-Side_Access_Control
https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
http://www.w3.org/TR/cors/
https://en.wikipedia.org/wiki/JSONP
Related
I'm trying to implement a simple Web Service (running on an Arduino board using an Ethernet shield) that can provide (push) information to a subscribed client by means of Reverse-AJAX.
The web service hosts a single web page that presents information from a (2D-LIDAR) sensor connected to that server board. Whenever the sensor output changes (very frequently and rapidly) the clients viewing that page should be instantly updated. For this application Reverse-AJAX / AJAX Push seems to be the option of choice, however I'm struggling to get the server part working.
This is what's in my aforementioned web page to "listen" for updates:
var xhr = new XMLHttpRequest();
xhr.multipart = true;
xhr.open( 'GET', 'push', true) ;
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
processEvents( window.JSON.parse( xhr.responseText ) );
}
}
xhr.send( null );
I'd like to keep the XmlHttpRequest running forever and have it call the processEvents function whenever a chunk of (JSON) data comes in from the server side. However I'm not sure what the server response, especially the HTTP response header should look like to make this work as expected.
Whenever I have the server send a HTTP response header like this
HTTP/1.1 200 OK\r\n
Connection: keep-alive\r\n
Content-Length: 100\r\n
Content-Type: text/json\r\n
\r\n
the XmlHttpRequest finishes after receiving exactly one "chunk" of data. I also tried without "Content-Length" header, but "Content-Type: multipart/mixed; boundary=..." or "Transfer-Encoding: chunked" but both never happened to fire processEvents, supposedly because the browser was waiting for the response to complete, whatever that means.
I'm therefore looking for a working example of such a HTTP Response to an AJAX-Push request. What does a HTTP Response generally need to look like to be accepted by the indefinitely running XmlHttpRequest and to fire processEvents whenever new data arrives?
Btw. I tried those things using Firefox 64.0.
if you a looking for a low latency http based comm you should take a look at websockets. Your xmlhttp with Post method will have a high latency of about 50 milliseconds , trust me, I tried to develop a rgb controller based on a rainbow color picker before, either sync and asynchronous post methods wasn’t working well for me, the script just hold waiting for a response.
Now to answer you question specifically, download postman, a software that allows you to simulate all the http methods requests and headers you wish to. Also gives you the code to implement in many languages, and don’t forget f12 on chrome > network tab, this way you can check how the output of or http requests are being handled
I'm writing a simple api for training using express. Here's my testing code:
var express = require('express');
var app = express();
app.post("/api/:var_name", function(req, res) {
res.send(req.params.var_name);
});
is simply testing to see if POST is working. When I call http://localhost:3000/api/1 I get Cannot GET /api/1, so the server is obviously interpreting the POST request as GET, what do I need to do to call POST instead?
Anything you call in the address bar of your browser will be sent via get. This is due to the fact that post-messages (and almost all other methods) do have a body-part. But there is no way for your browser to send additional information inside the body of the http packet.
If you want to test your routes for any method other than GET I would suggest you download a tool like postman.
https://www.getpostman.com/
BEWARE: This is my preference. You can of curse also use text based browsers like curl to test it.
The server interprets the request according to the verb you set in the HTTP request. If no method/verb is specified it is interpreted as GET(not sure about this part).
When you call that URL, you need to use the method as well. For example if you use the fetch API, you can call it like:
fetch(url, {method:"POST"})
If you're entering it in your browser and expect it to be interpreted as a post request, it's not. All browser url requests are GET. Use a tool like Postman to call different HTTP verbs. It's really useful when creating such APIs.
You can check out this answer on details of how to add body and headers to a post request: Fetch: POST json data
I have a REST server which returns a Link HTTP header with a response to a PUT to indicate the URL of the newly-created entity:
Link:<entities/6>; rel="created"
Is there any possibility to read that link header with Restangular?
The only facility to intercept HTTP requests with Restangular I've met so far is to register a response interceptor in the app config:
restangular.addResponseInterceptor(function (data, operation, what, url, response, deferred) {
console.log(response.headers())
return response.data;
});
However, with above demo implementation in place, the only HTTP header which gets logged is content-type. Still, I can see in the browser development toolbar that a response comes indeed with many additional HTTP response headers, such as Server, Date, and the aforementioned Link.
Why do I not have access to the full array of HTTP response headers through addResponseInterceptor()? Is there any way to capture the HTTP response header in question using Restangular?
Note: I don't search for an answer using HAL or any other special response body format. I would rather like to know whether I can use plain HTTP headers with Restangular or not (if not, I will probably resort to HAL or something).
You don't need a ResponseInterceptor to do this. You just need to set fullResponse to true to get the whole response (including the http headers) every time you do any request.
Restangular.setFullResponse(true);
You can set it globally in your app configuration. Something like this:
angular.module('YourApp')
.config(['RestangularProvider',
function (RestangularProvider) {
RestangularProvider.setFullResponse(true);
...
Then, every time you receive a response, you can access all the response headers.
Restangular.all('users').getList().then(function(response) {
$scope.users = response.data;
console.log(response.headers);
}
Example:
response.headers('Link')
NOTE: Be careful because using fullResponse, the response data is located in response.data, not directly in response.
EDIT: As #STEVER points, you also need to expose the headers in your server API.
Example:
Access-Control-Expose-Headers: Link
You can get more detailed information in Restangular documentation
Hope it helps.
I'm trying to do a POST to a service running on localhost with jQuery AJAX, but it keeps returning status code 0 even after I've set jQuery.support.cors = true. I can also navigate to my WCF REST service successfully from my browser. This is what my JavaScript looks like:
<script>
jQuery.support.cors = true;
$(document).ready(function(){
$.ajax({
type: "POST",
url: "http://localhost:8000/Test",
data: '{"test":"test"}',
contentType: "application/json",
dataType: "json",
success: function (msg) {
alert('success');
},
error:function(x,e){
if(x.status==0){
alert('error 0');
}
}
});
});
</script>
Does anyone know what could be causing this? I should also mention that I can't POST to anything on localhost using jQuery.
According to Fiddler, the JSON data is not sent, and a HTTP OPTIONS is done instead of a POST.
try this
var dataObj = {test:"test"};
var json = JSON.stringify(dataObj);
then in your ajax call
data: json,
I didn't want to spend anymore time on this issue, so I resorted to using raw HTML form POST as the usage of JSON wasn't essential in my case.
For anyone else having the same issues outlined in the original post, see this thread for an explanation and a solution: Problem sending JSON data from JQuery to WCF REST method
To summarize, your service needs to be able to handle the HTTP OPTIONS method if it is expected to respond to cross domain calls.
You should use a tool like network monitor etc. to see if the browser is asking the server for the allowed headers (using the OPTIONS header request), you may need to supply the correct headers in an OPTIONS response before the actual request is sent to the server (see the article at the bottom).
Also, you could try adding this to the actual call or the ajaxSetup, as you will need to tell the browser to send credentials and allow the cross domain call (I know someone else already mentioned 'crossDomain'):
$.ajaxSetup({
crossDomain: true,
xhrFields: {
withCredentials: true
}
});
Have a read of this if you get time too.. https://developer.mozilla.org/en/http_access_control
So, when the request is cross domain, jQuery will send your post request as a get request anyways.
Are you accessing "localhost" in the URL but then your application is sending the requests to the local IP of your machine instead of localhost? Because that's technically cross-domain, which means that you won't receive the request in the expected manner.
E.g. (just tested this locally)
Visiting my local site at:
http://localhost/test/
A form on the site submits to my local ip address instead of localhost via $.post():
<form action="http://10.0.0.17/test/" method="post">
....[form stuff...]
</form>
This is a cross-domain request
If you're calling $.post() or jquery's ajax() call set to post, it automatically moves your parameters from the post body into the query string.
If you ARE accessing local host, try hitting the site via whatever address your jquery post() method is using as the domain and see if that helps.
See more on cross-domain policies:
http://en.wikipedia.org/wiki/Same_origin_policy
Send the data as an Object literal instead of a string
data: '{"test":"test"}',
to
data: {test:"test"},
I need to POST data to a server in a different domain. That server is using SSL and expects the data to be in the form of a JSON string. I am attempting to do this from javascript.
I create the data and use JSON.stringify() to get it into the correct format. Then I send it as follows:
var url = "https://api.postageapp.com/v.1.0/send_message.json";
http=new XMLHttpRequest();
http.open("POST", url, true);
http.setRequestHeader("Content-type", "application/json");
http.setRequestHeader("Connection", "close");
// create the data in a data structure named post_data
var JSONText = JSON.stringify(post_data);
http.send(JSONText);
Doing a packet trace I see my client do a handshake with the server but then twice the server replies with "Encrypted alert" including the last time it sends a packet back. The browser debugger always shows a 405 - Method Now Allowed error.
What am I missing to get this to work? When they try it within their domain it runs fine.
You need server to return a HTTP Header like that:
header('Access-Control-Allow-Origin: *');
Live example:
Making cross domain JavaScript requests using XMLHttpRequest or XDomainRequest
You cannot do a cross domain post like that.
Alternative is to use Server side proxy (read this link for a nice explanation as to why you can't do that) or iframe approach.
Strictly speaking it should not be possible (due to security issues) however using a workaround called JSONP you can achieve this with a RESTful web service.
See the link below.
http://en.wikipedia.org/wiki/JSONP
MS has some code you can download somewhere on the internet with specific bindings the code is called.
JSONPBehaviour.cs
JSONPBindingElement.cs
JSONPBindingExtension.cs
JSONPEncoderFactory.cs