|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334 |
- # window.fetch polyfill
-
- The `fetch()` function is a Promise-based mechanism for programmatically making
- web requests in the browser. This project is a polyfill that implements a subset
- of the standard [Fetch specification][], enough to make `fetch` a viable
- replacement for most uses of XMLHttpRequest in traditional web applications.
-
- ## Table of Contents
-
- * [Read this first](#read-this-first)
- * [Installation](#installation)
- * [Usage](#usage)
- * [Importing](#importing)
- * [HTML](#html)
- * [JSON](#json)
- * [Response metadata](#response-metadata)
- * [Post form](#post-form)
- * [Post JSON](#post-json)
- * [File upload](#file-upload)
- * [Caveats](#caveats)
- * [Handling HTTP error statuses](#handling-http-error-statuses)
- * [Sending cookies](#sending-cookies)
- * [Receiving cookies](#receiving-cookies)
- * [Obtaining the Response URL](#obtaining-the-response-url)
- * [Aborting requests](#aborting-requests)
- * [Browser Support](#browser-support)
-
- ## Read this first
-
- * If you believe you found a bug with how `fetch` behaves in your browser,
- please **don't open an issue in this repository** unless you are testing in
- an old version of a browser that doesn't support `window.fetch` natively.
- This project is a _polyfill_, and since all modern browsers now implement the
- `fetch` function natively, **no code from this project** actually takes any
- effect there. See [Browser support](#browser-support) for detailed
- information.
-
- * If you have trouble **making a request to another domain** (a different
- subdomain or port number also constitutes another domain), please familiarize
- yourself with all the intricacies and limitations of [CORS][] requests.
- Because CORS requires participation of the server by implementing specific
- HTTP response headers, it is often nontrivial to set up or debug. CORS is
- exclusively handled by the browser's internal mechanisms which this polyfill
- cannot influence.
-
- * This project **doesn't work under Node.js environments**. It's meant for web
- browsers only. You should ensure that your application doesn't try to package
- and run this on the server.
-
- * If you have an idea for a new feature of `fetch`, **submit your feature
- requests** to the [specification's repository](https://github.com/whatwg/fetch/issues).
- We only add features and APIs that are part of the [Fetch specification][].
-
- ## Installation
-
- ```
- npm install whatwg-fetch --save
- ```
-
- You will also need a Promise polyfill for [older browsers](http://caniuse.com/#feat=promises).
- We recommend [taylorhakes/promise-polyfill](https://github.com/taylorhakes/promise-polyfill)
- for its small size and Promises/A+ compatibility.
-
- ## Usage
-
- For a more comprehensive API reference that this polyfill supports, refer to
- https://github.github.io/fetch/.
-
- ### Importing
-
- Importing will automatically polyfill `window.fetch` and related APIs:
-
- ```javascript
- import 'whatwg-fetch'
-
- window.fetch(...)
- ```
-
- If for some reason you need to access the polyfill implementation, it is
- available via exports:
-
- ```javascript
- import {fetch as fetchPolyfill} from 'whatwg-fetch'
-
- window.fetch(...) // use native browser version
- fetchPolyfill(...) // use polyfill implementation
- ```
-
- This approach can be used to, for example, use [abort
- functionality](#aborting-requests) in browsers that implement a native but
- outdated version of fetch that doesn't support aborting.
-
- For use with webpack, add this package in the `entry` configuration option
- before your application entry point:
-
- ```javascript
- entry: ['whatwg-fetch', ...]
- ```
-
- ### HTML
-
- ```javascript
- fetch('/users.html')
- .then(function(response) {
- return response.text()
- }).then(function(body) {
- document.body.innerHTML = body
- })
- ```
-
- ### JSON
-
- ```javascript
- fetch('/users.json')
- .then(function(response) {
- return response.json()
- }).then(function(json) {
- console.log('parsed json', json)
- }).catch(function(ex) {
- console.log('parsing failed', ex)
- })
- ```
-
- ### Response metadata
-
- ```javascript
- fetch('/users.json').then(function(response) {
- console.log(response.headers.get('Content-Type'))
- console.log(response.headers.get('Date'))
- console.log(response.status)
- console.log(response.statusText)
- })
- ```
-
- ### Post form
-
- ```javascript
- var form = document.querySelector('form')
-
- fetch('/users', {
- method: 'POST',
- body: new FormData(form)
- })
- ```
-
- ### Post JSON
-
- ```javascript
- fetch('/users', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json'
- },
- body: JSON.stringify({
- name: 'Hubot',
- login: 'hubot',
- })
- })
- ```
-
- ### File upload
-
- ```javascript
- var input = document.querySelector('input[type="file"]')
-
- var data = new FormData()
- data.append('file', input.files[0])
- data.append('user', 'hubot')
-
- fetch('/avatars', {
- method: 'POST',
- body: data
- })
- ```
-
- ### Caveats
-
- * The Promise returned from `fetch()` **won't reject on HTTP error status**
- even if the response is an HTTP 404 or 500. Instead, it will resolve normally,
- and it will only reject on network failure or if anything prevented the
- request from completing.
-
- * For maximum browser compatibility when it comes to sending & receiving
- cookies, always supply the `credentials: 'same-origin'` option instead of
- relying on the default. See [Sending cookies](#sending-cookies).
-
- #### Handling HTTP error statuses
-
- To have `fetch` Promise reject on HTTP error statuses, i.e. on any non-2xx
- status, define a custom response handler:
-
- ```javascript
- function checkStatus(response) {
- if (response.status >= 200 && response.status < 300) {
- return response
- } else {
- var error = new Error(response.statusText)
- error.response = response
- throw error
- }
- }
-
- function parseJSON(response) {
- return response.json()
- }
-
- fetch('/users')
- .then(checkStatus)
- .then(parseJSON)
- .then(function(data) {
- console.log('request succeeded with JSON response', data)
- }).catch(function(error) {
- console.log('request failed', error)
- })
- ```
-
- #### Sending cookies
-
- For [CORS][] requests, use `credentials: 'include'` to allow sending credentials
- to other domains:
-
- ```javascript
- fetch('https://example.com:1234/users', {
- credentials: 'include'
- })
- ```
-
- To disable sending or receiving cookies for requests to any domain, including
- the current one, use the "omit" value:
-
- ```javascript
- fetch('/users', {
- credentials: 'omit'
- })
- ```
-
- The default value for `credentials` is "same-origin".
-
- The default for `credentials` wasn't always the same, though. The following
- versions of browsers implemented an older version of the fetch specification
- where the default was "omit":
-
- * Firefox 39-60
- * Chrome 42-67
- * Safari 10.1-11.1.2
-
- If you target these browsers, it's advisable to always specify `credentials:
- 'same-origin'` explicitly with all fetch requests instead of relying on the
- default:
-
- ```javascript
- fetch('/users', {
- credentials: 'same-origin'
- })
- ```
-
- #### Receiving cookies
-
- As with XMLHttpRequest, the `Set-Cookie` response header returned from the
- server is a [forbidden header name][] and therefore can't be programmatically
- read with `response.headers.get()`. Instead, it's the browser's responsibility
- to handle new cookies being set (if applicable to the current URL). Unless they
- are HTTP-only, new cookies will be available through `document.cookie`.
-
- #### Obtaining the Response URL
-
- Due to limitations of XMLHttpRequest, the `response.url` value might not be
- reliable after HTTP redirects on older browsers.
-
- The solution is to configure the server to set the response HTTP header
- `X-Request-URL` to the current URL after any redirect that might have happened.
- It should be safe to set it unconditionally.
-
- ``` ruby
- # Ruby on Rails controller example
- response.headers['X-Request-URL'] = request.url
- ```
-
- This server workaround is necessary if you need reliable `response.url` in
- Firefox < 32, Chrome < 37, Safari, or IE.
-
- #### Aborting requests
-
- This polyfill supports
- [the abortable fetch API](https://developers.google.com/web/updates/2017/09/abortable-fetch).
- However, aborting a fetch requires use of two additional DOM APIs:
- [AbortController](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) and
- [AbortSignal](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal).
- Typically, browsers that do not support fetch will also not support
- AbortController or AbortSignal. Consequently, you will need to include
- [an additional polyfill](https://github.com/mo/abortcontroller-polyfill#readme)
- for these APIs to abort fetches:
-
- ```js
- import 'abortcontroller-polyfill/dist/abortcontroller-polyfill-only'
- import {fetch} from 'whatwg-fetch'
-
- // use native browser implementation if it supports aborting
- const abortableFetch = ('signal' in new Request('')) ? window.fetch : fetch
-
- const controller = new AbortController()
-
- abortableFetch('/avatars', {
- signal: controller.signal
- }).catch(function(ex) {
- if (ex.name === 'AbortError') {
- console.log('request aborted')
- }
- })
-
- // some time later...
- controller.abort()
- ```
-
- ## Browser Support
-
- - Chrome
- - Firefox
- - Safari 6.1+
- - Internet Explorer 10+
-
- Note: modern browsers such as Chrome, Firefox, Microsoft Edge, and Safari contain native
- implementations of `window.fetch`, therefore the code from this polyfill doesn't
- have any effect on those browsers. If you believe you've encountered an error
- with how `window.fetch` is implemented in any of these browsers, you should file
- an issue with that browser vendor instead of this project.
-
-
- [fetch specification]: https://fetch.spec.whatwg.org
- [cors]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
- "Cross-origin resource sharing"
- [csrf]: https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet
- "Cross-site request forgery"
- [forbidden header name]: https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name
|