4

I am trying to post some json to a sharepoint url, as in this example. The example uses node, but I am trying to do it in the browser.

I tried it with fetch first:

fetch("https://outlook.office365.com/webhook/...", 
            {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json;'
            },
            body: JSON.stringify(this.groupCardBody()),
        })

From that i got the error:

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:1234' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

But i don't have control over the response, and if i add mode: 'no-cors' into the fetch options as it suggests, it strips the content-type header and returns 415 Unsupported Media Type.

So i tried it with a simple xhttp request and that fails too as it does the preflight and doesn't get the right headers back:

    let xhr = new XMLHttpRequest()
    xhr.open("POST", "https://outlook.office365.com/webhook/...");
    xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8");
    xhr.send(JSON.stringify(this.groupCardBody()));

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

The request library used in the example was quite difficult to get working in the browser and by no means lightweight (added almost 2MB to my webpacked script), so any suggestions about how to get round this are welcome I am pretty stuck, all my searches turn up answers for fixing the server and i don't have that option.

UPDATE

As suggested in the accepted answer, I solved it by posting the json back to the server and making the post from there, got it working with something as simple as the following:

Client:

fetch("PostGroupCard?json="+
    encodeURI(JSON.stringify(this.groupCardBody())),
    {credentials: "same-origin"}
)

Server:

Function PostGroupCard(json As String)
    Dim wr = WebRequest.Create("https://outlook.office365.com/webhook/...")
    wr.ContentType = "application/json"
    wr.Method = "POST"

    Using sw = New StreamWriter(wr.GetRequestStream())
        sw.Write(json)
        sw.Flush()
        sw.Close()
    End Using

    Dim r = wr.GetResponse()
    Using sr = New StreamReader(r.GetResponseStream())
        Dim result = sr.ReadToEnd()
    End Using

End Sub
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
  • 2
    As long as the request sends JSON, a preflight is required with client-side APIs. [Non-preflighted requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests) only permit the request's `Content-Type` to be URL-encoded, multi-part form data, or plain text. If it has to be JSON and without a preflight request, you'll have to make the actual request to SharePoint server-side, where the same-origin policy doesn't apply. – Jonathan Lonowski May 23 '16 at 21:09
  • 2
    get rid of the custom content-type header and it should work... – dandavis May 23 '16 at 21:09
  • 1
    use jsonp http://stackoverflow.com/questions/3839966/can-anyone-explain-what-jsonp-is-in-layman-terms – Alexan May 23 '16 at 21:09
  • 1
    @Alex: there is no POST in JSONP, nor can JSONP get a formal response if something goes wrong... – dandavis May 23 '16 at 21:10
  • 1
    If I remove the custom header, I get the same error. –  May 23 '16 at 21:16
  • 3
    To clarify my previous comment: You can't force cross-origin requests to work from the client-side. The server will have to provide support for CORS and give your application permission to make the request. If it doesn't, at either part, the request can't be made client-side, where the same-origin policy applies. You'll have to involve a server-side layer to make the actual request, since the same-origin policy won't apply there, and have the client send its request to that. – Jonathan Lonowski May 23 '16 at 21:17
  • 1
    @JonathanLonowski right that makes a lot of sense why my searches were stumping me, if you want to put that in an answer and suggest i post back to my own server and post the json from there i will accept that. just needed to think outside the box a bit! –  May 23 '16 at 21:19
  • @dandavis the server wouldn't accept it without the json content-type, so i had to go the server route –  May 23 '16 at 22:12

1 Answers1

0

Most of this answer is taken from the comments.

For security reasons, you cannot make an XMLHTTPRequest unless you are on the same origin or CORS header from the other domain says you can. If this were possible, any site could preform malicious actions like hack you accounts.

Two alternatives to consider would be JSONP and having your server act as a proxy to access the other domain.

michaelmesser
  • 3,601
  • 2
  • 19
  • 42
  • I did go down the server route, so part of this answer is right but it is not entirely correct. –  May 23 '16 at 22:02