fetch() does not send headers?

70,708

Solution 1

The same-origin policy restricts the kinds of requests that a Web page can send to resources from another origin.

In the no-cors mode, the browser is limited to sending “simple” requests — those with safelisted methods and safelisted headers only.

To send a cross-origin request with headers like Authorization and X-My-Custom-Header, you have to drop the no-cors mode and support preflight requests (OPTIONS).

The distinction between “simple” and “non-simple” requests is for historical reasons. Web pages could always perform some cross-origin requests through various means (such as creating and submitting a form), so when Web browsers introduced a principled means of sending cross-origin requests (cross-origin resource sharing, or CORS), it was decided that such “simple” requests could be exempt from the preflight OPTIONS check.

Solution 2

Firstly : Use an object instead of new Headers(..):

fetch('www.example.net', {
  method: 'POST',
  headers: {
    'Content-Type': 'text/plain',
    'X-My-Custom-Header': 'value-v',
    'Authorization': 'Bearer ' + token,
  }
});

Secondly : Good to know, headers are lowercased by fetch!!

Thirdly : no-cors mode limits the use of headers to this white list :

  • Accept
  • Accept-Language
  • Content-Language
  • Content-Type and whose value is ( application/x-www-form-urlencoded, multipart/form-data, text/plain )

That's why only your Content-Type header is sent and not X-My-Custom-Header or Authorization.

Solution 3

Can you try this?

fetch(serverEndpoint, {  
  credentials: 'include'  
})

Ref. https://developers.google.com/web/updates/2015/03/introduction-to-fetch#sending_credentials_with_a_fetch_request

Solution 4

I also had this same issue. I resolved it by removing 'no-cors' from javascript and adding the following in server side spring boot.

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity httpSecurity) throws Exception {
             .antMatchers(HttpMethod.OPTIONS, "/**").permitAll()

        }
    }
Share:
70,708

Related videos on Youtube

Rasto
Author by

Rasto

Entrepreneur, UX consultant, full-stack developer with strongest competency in Swift & iOS. Can get die-hard about top-notch UX and code quality. Diving deeper into React and getting excited about GraphQL. My pro history chapters are written in C#, Objective-C, Java, JS, TS, Flow, even Haskel, Prolog & Pascal. Sports and outdoor enthusiast. Love exploring cultures around the world. Found in mountains in the winter and at seaside during summer. Amater photographer. Always happy to learn and share what I learned e.g. externally giving lectures at my alma mater.

Updated on June 03, 2020

Comments

  • Rasto
    Rasto almost 4 years

    I am sending POST request like this from browser:

    fetch(serverEndpoint, {
        method: 'POST',
        mode: 'no-cors', // this is to prevent browser from sending 'OPTIONS' method request first
        redirect: 'follow',
        headers: new Headers({
                'Content-Type': 'text/plain',
                'X-My-Custom-Header': 'value-v',
                'Authorization': 'Bearer ' + token,
        }),
        body: companyName
    })
    

    By the time the request reaches my back-end it does not contain X-My-Custom-Header nor Authorization header.

    My back-end is Google Cloud function for Firebase (basically just Node.js endpoint) that looks like this:

    exports.createCompany = functions.https.onRequest((req, res) => {
        let headers = ['Headers: ']
        for (let header in req.headers) {
            headers.push(`${header} : ${req.headers[header]}`)
        }
        console.log(headers)
        ...
    }
    

    The console log of that Google Cloud for Firebase function does not contain any X-My-Custom-Header nor Authorization header.

    What is wrong?


    Edit 1

    So using dev tools in Chrome a checked that neither X-My-Custom-Header nor Authorization header is send from the browser... The questions now are: Why? How do I fix it?


    Edit 2

    More information about my app: It's React app. I have disabled service worker. I have tried to create Request and specifically add headers using req.headers.append(). The headers still wouldn't send.

    • Joe Clay
      Joe Clay almost 7 years
      Is your browser actually sending the headers? Check your dev tools.
    • Rasto
      Rasto almost 7 years
      @JoeClay I am seasoned developer (mobile, backend) but rather new to web front-end development. Many tools are new for me - especially dev tools in brownser are not very good friend of mine yet. Can you suggest how to I check it on Chrome or Safari? Thanks
    • Joe Clay
      Joe Clay almost 7 years
      In Chrome, press F12 to open your dev tools, and then switch to the Network tab. When your application sends a HTTP request, it'll appear in the list, and you can click on it to view the headers/body of the request and response. See the docs for more info - learning how to use your browser's dev tools will help you loads if you're just starting out with web development :)
    • Rasto
      Rasto almost 7 years
      @JoeClay So the answer is no the browser does not send X-My-Custom-Header nor Authorization. Now the remaining questions are why? And how to fix it?
    • guest271314
      guest271314 almost 7 years
  • Rasto
    Rasto almost 7 years
    Great answer, thank you. However, not the answer that would make me happy. I am trying to add support fro CORS now.
  • Rasto
    Rasto almost 7 years
    @sideshowbarker yes, definitelly. It is. Just supporting CORS well does not seem to be very straightforward
  • Rasto
    Rasto almost 7 years
    @sideshowbarker Have a look on my profile, its age, badges and older questions. From that you should understand that I know what I asked and how to mark aswer accepted, thank you. If you really want to advice others what to do with answers and bounties you can do it on meta. As for this answer, I might only mark it as accepted once I have CORS supported on server. Without that I have no proof that this really works (and 500 is a lot of rep to spend on incorrect answer). Also, as you should know I have no obligation to mark it as accepted even if it works as I may wait for more/better answers.
  • Rasto
    Rasto almost 7 years
    The above being said, to avoid missunderstanding: I really like Vasiliy's answer for it's high quality and will most probably accepted if it works once I can get that CORS support working on back-end (Firebase functions).
  • CaptainHere
    CaptainHere almost 7 years
  • Sgnl
    Sgnl almost 7 years
    a note about the trailing comma, it's becoming a standard is ES2017 but people have been using it with Babel (babeljs.io/docs/plugins/syntax-trailing-function-commas) and also NodeJS has supported it since version 6.4.0. This shouldn't effect the OP as I've used trailing commas with fetch() before with success.
  • pungggi
    pungggi over 5 years
    This answers the questions "How to Fetch with Authorization header from Browser" stackoverflow.com/questions/49967188/…
  • pungggi
    pungggi over 5 years
    This answer does not address the first nor the second question. It just gives some syntax corrections.
  • GreenAsJade
    GreenAsJade over 5 years
    Is this missing some code? How can the method body start with '.'? Is that supposed to be HttpSecurity.?