最新的Web API接口中提供了一个全局fetch方法,从而以一种更为简单、合理的方式来支持跨网络异步获取资源。node
这种功能之前是使用 XMLHttpRequest实现的。Fetch提供了一个更好的替代方法,能够很容易地被其余技术使用,例如 Service Workers。Fetch还提供了单个逻辑位置来定义其余HTTP相关概念,例如CORS和HTTP的扩展。react
请注意,fetch规范与jQuery.ajax()主要有两种方式的不一样:git
一个基本的 fetch请求设置起来很简单。看看下面的代码:github
fetch('http://example.com/movies.json') .then(function(response) { return response.json(); }) .then(function(myJson) { console.log(myJson); });
这里咱们经过网络获取一个JSON文件并将其打印到控制台。最简单的用法是只提供一个参数用来指明想fetch()到的资源路径,而后返回一个包含响应结果的promise(一个 Response 对象)。ajax
fetch() 接受第二个可选参数,一个能够控制不一样配置的 init 对象:编程
参考 fetch(),查看全部可选的配置和更多描述。json
postData('http://example.com/answer', {answer: 42}) .then(data => console.log(data)) // JSON from `response.json()` call .catch(error => console.error(error)) function postData(url, data) { // Default options are marked with * return fetch(url, { body: JSON.stringify(data), // must match 'Content-Type' header cache: 'no-cache', // *default, no-cache, reload, force-cache, only-if-cached credentials: 'same-origin', // include, same-origin, *omit headers: { 'user-agent': 'Mozilla/4.0 MDN Example', 'content-type': 'application/json' }, method: 'POST', // *GET, POST, PUT, DELETE, etc. mode: 'cors', // no-cors, cors, *same-origin redirect: 'follow', // manual, *follow, error referrer: 'no-referrer', // *client, no-referrer }) .then(response => response.json()) // parses response to JSON }
为了让浏览器发送包含凭据的请求(即便是跨域源),要将credentials: 'include'添加到传递给 fetch()方法的init对象。redux
fetch('https://example.com', { credentials: 'include' })
若是你只想在请求URL与调用脚本位于同一块儿源处时发送凭据,请添加credentials: 'same-origin'。跨域
// The calling script is on the origin 'https://example.com' fetch('https://example.com', { credentials: 'same-origin' })
要改成确保浏览器不在请求中包含凭据,请使用credentials: 'omit'。promise
fetch('https://example.com', { credentials: 'omit' })
下面的示例片段展现了使用fetch()方法以POST方式发送 JSON编码的数据:
var url = 'https://example.com/profile'; var data = {username: 'example'}; fetch(url, { method: 'POST', // or 'PUT' body: JSON.stringify(data), // data can be `string` or {object}! headers: new Headers({ 'Content-Type': 'application/json' }) }).then(res => res.json()) .catch(error => console.error('Error:', error)) .then(response => console.log('Success:', response));
在最新浏览器API编程中,你可使用一个HTML <input type="file" /> 输入元素,并结合FormData() 函数和fetch()函数实现上传文件:
var formData = new FormData(); var fileField = document.querySelector("input[type='file']"); formData.append('username', 'abc123'); formData.append('avatar', fileField.files[0]); fetch('https://example.com/profile/avatar', { method: 'PUT', body: formData }) .then(response => response.json()) .catch(error => console.error('Error:', error)) .then(response => console.log('Success:', response));
若是遇到网络故障,fetch() (实际上是一个promise对象)将会Reject,带上一个 TypeError 对象。虽然这个状况常常是遇到了权限问题或相似问题——好比 404 不是一个网络故障。想要精确的判断 fetch() 是否成功,须要包含 promise解析的状况,此时再判断 Response.ok 是否是为 true。相似如下代码:
fetch('flowers.jpg').then(function(response) { if(response.ok) { return response.blob(); } throw new Error('Network response was not ok.'); }).then(function(myBlob) { var objectURL = URL.createObjectURL(myBlob); myImage.src = objectURL; }).catch(function(error) { console.log('There has been a problem with your fetch operation: ', error.message); });
除了传给 fetch() 一个资源的地址,你还能够经过使用 Request() 构造函数来建立一个 request 对象,而后再做为参数传给 fetch():
var myHeaders = new Headers(); var myInit = { method: 'GET', headers: myHeaders, mode: 'cors', cache: 'default' }; var myRequest = new Request('flowers.jpg', myInit); fetch(myRequest).then(function(response) { return response.blob(); }).then(function(myBlob) { var objectURL = URL.createObjectURL(myBlob); myImage.src = objectURL; });
Request() 和 fetch() 接受一样的参数。你甚至能够传入一个已存在的 request 对象来创造一个拷贝:
var anotherRequest = new Request(myRequest,myInit);
这个颇有用,由于 request 和 response bodies 只能被使用一次(译者注:这里的意思是由于设计成了 stream 的方式,因此它们只能被读取一次)。建立一个拷贝就能够再次使用 request/response 了,固然也可使用不一样的 init 参数。
要在不支持的浏览器中使用Fetch,可使用Fetch Polypill(https://github.com/github/fetch)。
上面示例中使用了 fetch API。它是替代 XMLHttpRequest 用来发送网络请求的很是新的 API。因为目前大多数浏览器原生还不支持它,React开发中建议你使用 cross_fetch 库(https://github.com/lquixada/cross-fetch):
// 每次使用 `fetch` 前都这样调用一下 import fetch from 'cross_fetch'
在底层,它在浏览器端使用 whatwg-fetch polyfill,在服务器端使用 node-fetch,因此若是当你把应用改为 同构 时,并不须要改变 API 请求。
注意,fetch polyfill 假设你已经使用了 Promise 的 polyfill。确保你使用 Promise polyfill 的一个最简单的办法是在全部应用代码前启用 Babel 的 ES6 polyfill:
// 在应用中其它任何代码执行前调用一次 import 'babel-polyfill'
import fetch from 'cross-fetch'
export const REQUEST_POSTS = 'REQUEST_POSTS'
function requestPosts(subreddit) {
return {
type: REQUEST_POSTS,
subreddit
}
}
export const RECEIVE_POSTS = 'RECEIVE_POSTS'
function receivePosts(subreddit, json) {
return {
type: RECEIVE_POSTS,
subreddit,
posts: json.data.children.map(child => child.data),
receivedAt: Date.now()
}
}
export const INVALIDATE_SUBREDDIT = ‘INVALIDATE_SUBREDDIT’
export function invalidateSubreddit(subreddit) {
return {
type: INVALIDATE_SUBREDDIT,
subreddit
}
}
// 来看一下咱们写的第一个 thunk action 建立函数!
// 虽然内部操做不一样,你能够像其它 action 建立函数 同样使用它:
// store.dispatch(fetchPosts('reactjs'))
export function fetchPosts(subreddit) {
// Thunk middleware 知道如何处理函数。
// 这里把 dispatch 方法经过参数的形式传给函数,
// 以此来让它本身也能 dispatch action。
return function (dispatch) {
// 首次 dispatch:更新应用的 state 来通知 // API 请求发起了。 dispatch(requestPosts(subreddit)) // thunk middleware 调用的函数能够有返回值, // 它会被看成 dispatch 方法的返回值传递。 // 这个案例中,咱们返回一个等待处理的 promise。 // 这并非 redux middleware 所必须的,但这对于咱们而言很方便。 return fetch(`http://www.subreddit.com/r/${subreddit}.json`) .then( response => response.json(), // 不要使用 catch,由于会捕获 // 在 dispatch 和渲染中出现的任何错误, // 致使 'Unexpected batch number' 错误。 // https://github.com/facebook/react/issues/6895 error => console.log('An error occurred.', error) ) .then(json => // 能够屡次 dispatch! // 这里,使用 API 请求结果来更新应用的 state。 dispatch(receivePosts(subreddit, json)) )
}}