4

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?

Community
  • 1
  • 1
MyDaftQuestions
  • 4,487
  • 17
  • 63
  • 120

2 Answers2

1

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>
Nick Painter
  • 720
  • 10
  • 13
  • 1
    Correct, I would suggest value for `Access-Control-Allow-Origin` should be set to WebsiteA(from where you are sending AJAX request) and not * – imVJ Sep 14 '15 at 18:55
  • @imVJ Definitely. This is an important point to remember. In most cases * should not be used for a production site unless you really want to enable cross origin requests for all domains. – Nick Painter Jun 01 '17 at 15:28
1

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