[AJAX] axios fetch cross-domain (2)

1.axios

1.1 What is axios?

  1. The most popular ajax request library on the front end
  2. react/vue officially recommends using axios to send ajax requests
  3. Documentation:https://github.com/axios/axiosopen

1.2 Features of axios

  1. Asynchronous ajax request library based on xhr + promise
  2. Both browser and node can be used
  3. Support for request/response interceptors
  4. Support Request Cancellation
  5. Request/Response Data Conversion
  6. Batch multiple requests

1.3 Axios common syntax

axios(config): the general/most essential way to send any type of request

axios(url[, config]): You can only specify the url to send a get request

axios.request(config): equivalent to axios(config)

axios.get(url[, config]): send a get request

axios.delete(url[, config]): send delete request

axios.post(url[, data, config]): send a post request

axios.put(url[, data, config]): send put request

axios.defaults.xxx: The default global configuration of the request (method\baseURL\params\timeout…)

axios.interceptors.request.use(): add request interceptor

axios.interceptors.response.use(): add response interceptor

axios.create([config]): Create a new axios (it does not have the following functions)

axios.Cancel(): Error object used to create a cancellation request

axios.CancelToken(): A token object used to create a cancellation request

axios.isCancel(): Is it an error to cancel the request

axios.all(promises): used to execute multiple asynchronous requests in batches

axios.spread(): A method used to specify a callback function that receives all successful data

image-20220625194840070

1.4 use

Commonly used configuration items for configuration objects
{
    
    
  // 路径url
  url: '/user',

  // 请求方法,默认get
  method: 'get', 

  //基础url,最终请求的url是 baseURL+url拼接,所以再全局设置默认,可以使得发送请求时的url变得简洁
  baseURL: 'https://some-domain.com/api/',

  //设置请求头
  headers: {
    
    'X-Requested-With': 'XMLHttpRequest'},

  //设置请求url的query参数,可以使得url简洁。
  //比如url是https://some-domain.com/api/user  然后params如下设置,那么最终的url是:
  //https://some-domain.com/api/user?ID=12345&name=Jack
  params: {
    
    
    ID: 12345,
    name:"Jack"
  },


 //设置请求体
  data: {
    
    
    firstName: 'Fred'
  },

  //设置请求的另外一种格式,不过这个是直接设置字符串的
  data: 'Country=Brasil&City=Belo Horizonte',

 //请求超时,单位毫秒,默认0,不超时。
  timeout: 1000,

  //响应数据类型,默认json
  responseType: 'json', 

  //响应数据的编码规则,默认utf-8
  responseEncoding: 'utf8',

  //响应体的最大长度 
  maxContentLength: 2000,

  // 请求体的最大长度
  maxBodyLength: 2000,

  //设置响应状态码为多少时是成功,调用resolve,否则调用reject失败
  //默认是大于等于200,小于300
  validateStatus: function (status) {
    
    
    return status >= 200 && status < 300; 
  }

the code

    <button id="btn1">发送get请求</button> <br><br>
    <button id="btn2">发送post请求</button><br><br>
    <button id="btn3">发送put请求</button><br><br>
    <button id="btn4">发送delete请求</button>

    <hr>

    <div>其他发送请求的api:</div><br><br>
    <button id="btn5">发送get请求1</button> <br><br>
    <button id="btn6">发送post请求1</button><br><br>
    <button id="btn7">发送put请求1</button><br><br>
    <button id="btn8">发送delete请求1</button>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
    //发送get
    document.getElementById("btn1").onclick = function(){
    
    
       axios({
    
    
        method:"GET",
        url:"http://localhost:3000/posts/1"
       }).then(response=>{
    
    
           console.log(response);
       })
    };

    //发送post
    document.getElementById("btn2").onclick = function(){
    
    
       axios({
    
    
        method:"POST",
        url:"http://localhost:3000/posts",
        data:{
    
    
            title:"axios学习",
            author:"Yehaocong"
        }
       }).then(response=>{
    
    
           console.log(response);
       })
    };
    //发送put
    document.getElementById("btn3").onclick = function(){
    
    
       axios({
    
    
        method:"PUT",
        url:"http://localhost:3000/posts/2",
        data:{
    
    
            title:"axios学习",
            author:"Liaoxiaoyan"
        }
       }).then(response=>{
    
    
           console.log(response);
       })
    };
    document.getElementById("btn4").onclick = function(){
    
    
       axios({
    
    
        method:"DELETE",
        url:"http://localhost:3000/posts/2",
       }).then(response=>{
    
    
           console.log(response);
       })
    };

    //其他发送请求的api
    document.getElementById("btn5").onclick = function(){
    
    
        //发送get,使用get,第一个参数时url,第二个参数时config配置对象
       axios.get("http://localhost:3000/posts/1")
       .then(response=>{
    
    
           console.log(response);
       })
    };

    //发送post
    document.getElementById("btn6").onclick = function(){
    
    
        //发送post请求,第一个参数时url,第二个参数时请求体,第三个参数时config配置对象
        axios.post("http://localhost:3000/posts",
        {
    
    title:"axios学习2",
            author:"Yehaocong2"})
            .then(response=>{
    
    
           console.log(response);
       })
    };
    //发送put,
    document.getElementById("btn7").onclick = function(){
    
    
        //发送put,接收三个参数,url  请求体 、 config配置对象
       axios.put("http://localhost:3000/posts/2",{
    
    title:"axios学习",
            author:"Liaoxiaoyan"})
       .then(response=>{
    
    
           console.log(response);
       })
    };
    document.getElementById("btn8").onclick = function(){
    
    
        //发送delete请求,接收2个参数, url config配置对象
        axios.delete("http://localhost:3000/posts/3")
       .then(response=>{
    
    
           console.log(response);
       })
    };

image-20220625195401372

default allocation

The global default configuration can be set to avoid multiple repeated configurations repeated in different requests, such as baseURL, timeout, etc., set baseURL here.

 axios.defaults.baseURL="http://localhost:3000";

 //因为上面配置了baseURL,所以我们之后的请求只需要配置url不用像之前那样的全路径
 axios.get("/posts/1")
.then(response=>{
    
    
    console.log(response);
})

1.5 Create a new axios object

Create a new axios according to the specified configuration, that is, each new axios has its own configuration new axios, but there is no method to cancel the request and send the request in batches. All other syntaxes are consistent. Why design this syntax?

Requirements: The configuration required by some interfaces in the project is different from that required by other interfaces, how to deal with it (for example, there are multiple baseURLs that need to be specified)

Solution: Create 2 new axios, each with its own unique configuration, which are applied to interface requests with different requirements

const instance = axios.create({
    
     // instance是函数类型
    baseURL: 'http://localhost:3000'
})
// 使用instance发Ajax请求
instance({
    
    
    url: '/posts'
})
instance.get('/posts')

1.6 Interceptors

Request interceptor (before sending the request, use the function to process and detect the parameters and content of the request, if there is a problem with the request, you can directly intercept -> cancel, last-in-first-execute = the subsequent request interceptor will be executed first)

Response interceptor (preprocess the result of the response, execute first = the previous response interceptor executes first)

1) Request interceptor:

  • Callback function executed before actually sending the request
  • Requests can be inspected or configured for specific handling
  • Failed callback function, the default passed is error
  • Successful callback function, the default passed is config (must also be)

2) Response Interceptor

  • Callback function to be executed after the request gets a response
  • Specific processing can be done on the response data
  • Successful callback function, the default passed is response
  • Failed callback function, the default passed is error

3) Request converter: a function for specific processing of request header and request body data

Response converter: a function that parses the response body json string into a js object or array

  • Explanation: Calling axios() does not send an ajax request immediately, but needs to go through a longer process
  • Process: request interceptor 2 => request interceptor 1 => send ajax request => response interceptor 1 => response interceptor 2 => request callback
  • Note: This process is chained through promises, the request interceptor passes config, and the response interceptor passes response

the code

script>
      //设置一个请求拦截器,在请求拦截器中可以对请求参数进行修改
      //config:配置对象
      axios.interceptors.request.use(
        function (config) {
    
    
          console.log("请求拦截器 成功 1号");
          // config.headers.test = "I am only a header!";
          //修改 config 中的参数
          config.params = {
    
     a: 100 };
          return config;
        },
        error => {
    
    
          console.log("请求拦截器 失败 1号");
          return Promise.reject(error);
        }
      );

      axios.interceptors.request.use(
        function (config) {
    
    
          config.timeout = 5000;
          console.log("请求拦截器 成功 2号");
          // config.headers.test = "I am only a header!";
          //修改 config 中的参数
          config.timeout = 2000;
          return config;
        },
        error => {
    
    
          console.log("请求拦截器 失败 2号");
          return Promise.reject(error);
        }
      );

      //设置一个响应拦截器,可以对响应结果做一些处理
      axios.interceptors.response.use(
        function (response) {
    
    
          console.log("响应拦截器 成功 1号");
            //返回到请求回调时,只要data数据
             return response.data;
        },
        function (error) {
    
    
          console.log("响应拦截器 失败 1号");
          return Promise.reject(error);
        }
      );

      //设置一个响应拦截器
      axios.interceptors.response.use(
        function (response) {
    
    
          console.log("响应拦截器 成功 2号");
          return response;
        },
        function (error) {
    
    
          console.log("响应拦截器 失败 2号");
          return Promise.reject(error);
        }
      );

      //发送请求
      axios({
    
    
        method: "GET",
        url: "http://localhost:3000/posts",
      })
        .then((response) => {
    
    
          console.log("自定义回调处理成功的结果");
          //console.log(response);
        })
        .catch((reason) => {
    
    
          console.log(reason);
        });
    </script>

image-20220625200618691

1.7 Cancellation Request

It can be used before version 0.22, and it has been deprecated since 0.22

  <body>
    <div class="container">
      <h1 class="page-header">axios取消请求</h1>
      <button class="btn btn-primary">发送请求</button>
      <button class="btn btn-warning">取消请求</button>
    </div>
  </body>
  <script>
    //获取按钮
    const btns = document.querySelectorAll("button");
    //2.声明一个全局变量
    let cancel = null;
    //发送请求
    btns[0].onclick = () => {
    
    
      //检测上一次请求是否已经完成
      if (cancel !== null) {
    
    
        //则代表上一次请求还未取消,故直接取消上一次请求
        cancel();
      }
      axios({
    
    
        method: "GET",
        url: "http://localhost:3000/posts",
        //1.添加配置对象的属性
        cancelToken: new axios.CancelToken((c) => {
    
    
          //3.将c的值赋值给cancel
          cancel = c;
        }),
      }).then((response) => {
    
    
        console.log(response);
        //当请求执行完后 将cancel进行初始化设置
        cancel = null;
      });
    };

    //取消请求
    btns[1].onclick = () => {
    
    
      cancel();
    };
  </script>

0.22 new method

<script src="https://cdn.bootcdn.net/ajax/libs/axios/0.27.2/axios.min.js"></script>
 let btn = document.querySelectorAll('button');
const controller = new AbortController();
      btn[0].onclick = function () {
    
    
          axios( {
    
    
              url:'https://api.uomg.com/api/get.kg?songurl=https://node.kg.qq.com/play?s=YaCv8EYfJunVWYcH',
              signal: controller.signal
              }).then(function(response) {
    
    
                  console.log(response);
              });
      }

      btn[1].onclick = function () {
    
    
        controller.abort()
      }

1.8 Encapsulating axios in vue

requests.js
//对于axios进行二次封装
import axios from 'axios';
//获取仓库:存储数据
import store from '@/store';

//axios.create方法执行,其实返回一个axios和request一样的
let requests = axios.create({
    
    
  //基础路径,发请求URL携带api【发现:真实服务器接口都携带/api】
  baseURL: '/api',
  //超时的设置
  timeout: 5000,
});

//请求拦截器:将来项目中【N个请求】,只要发请求,会触发请求拦截器!!!
requests.interceptors.request.use(config => {
    
    
  //请求拦截器:请求头【header】,请求头能否给服务器携带参数
  //请求拦截器:其实项目中还有一个重要的作用,给服务器携带请求们的公共的参数
  if (store.state.detail.nanoid_token) config.headers.userTempId = store.state.detail.nanoid_token;
  if (store.state.user.token) config.headers.token = store.state.user.token;

  return config;
});

//响应拦截器:请求数据返回会执行
requests.interceptors.response.use(
  res => {
    
    
    //res:实质就是项目中发请求、服务器返回的数据
    return res.data;
  },
  err => {
    
    
    //温馨提示:某一天发请求,请求失败,请求失败的信息打印出来
    alert(err.message);
    //终止Promise链
    return new Promise();
  }
);

//最后需要暴露:暴露的是添加新的功能的axios,即为requests
export default requests;

use

import requests from '@/api/requests';
//注册的接口
export const reqRegister = data =>
  requests({
    
     url: `/user/passport/register`, method: 'post', data });

2.fetch

2.1 Disadvantages of XMLHttpRequest

The browser provides a native AJAX implementation class XMLHttpRequest. Based on this class instance, we can send AJAX requests to the server on the web page.

But the design of XMLHttpRequest is not perfect, mainly in the following aspects:

  • HTTP requests and responses are coupled to the XMLHttpRequest instance, the structure is not simple enough
  • Using event callbacks to get HTTP responses may lead to callback hell
  • If the HTTP response data is too large, it will take up a lot of memory
  • The last point is that the steps of XMLHttpRequest to implement AJAX are too fragmented

2.2 Advantages of fetch

Fetch, like XMLHttpRequest, is also native to the browser and is used to send AJAX requests.

fetch

image-20220624220655195

It was born after XMLHttpRequest, which aims to solve the shortcomings of XMLHttpRequest, so the disadvantages of XMLHttpRequest are its advantages. The specific advantages are as follows

  • Simple syntax and clear structure
  • Support Promise to get asynchronous HTTP response
  • HTTP response supports streaming, memory-friendly

Fetch is designed as a function, and AJAX can be initiated by calling the fetch function, without creating an instance like XMLHttpRequest, and then initiating AJAX based on the xhr instance.

fetch('http://localhost:3000/test') // fetch函数调用即发起AJAX

The fetch function returns a Promise object, and the result value of the Promise object is the HTTP response

fetch('http://localhost:3000/test').then(response => {
    
     // fetch函数返回值是一个Promise类型对象
    console.log(response) // 该Promise对象的结果值response就是HTTP响应

The HTTP response of the result value of the Promise object returned by the fetch function is obtained in a streaming manner. Even if the HTTP response data is large, it will not occupy too much memory.

2.3 fetch request and response

2.3.1 Request

fetch(url,options).then((response)=>{
    
    
//处理http响应
},(error)=>{
    
    
//处理错误
})

url: is the address to send network requests.

options: send request parameters,

  • body - http request parameters

  • mode - the requested mode

    • cors: The default value, allowing cross-origin requests.
    • same-origin: Only same-origin requests are allowed.
    • no-cors: The request method is limited to GET, POST and HEAD, and only a few simple headers can be used, and cross-domain complex headers cannot be added, which is equivalent to the request that can be sent by submitting a form.
  • cache - user specified cache.

  • method - request method, default GET

  • signal - used to cancel the fetch

  • headers - HTTP request header settings

  • keepalive - When the page is unloaded, it tells the browser to keep the connection in the background and continue to send data.

  • credentials - whether to send cookies

    • same-origin: The default value, cookies are sent for same-origin requests, and not sent for cross-origin requests.
    • include: Cookies are always sent regardless of same-origin requests or cross-domain requests.
    • omit: Never send.
  • referrer - the header used to set fetch()the requestreferer

  • referrerPolicy - used to set

    Referer
    

    header rules

    • no-referrer-when-downgrade: The default value, always send the Referer header, except when requesting HTTP resources from HTTPS pages.
    • no-referrer: Do not send the Referer header.
    • origin: The Referer header only contains the domain name, not the full path.
    • origin-when-cross-origin: Same-origin request Referer header contains the full path, cross-origin request only contains the domain name.
    • same-origin: Referer is not sent for cross-origin requests, and same-origin requests are sent.
    • strict-origin: The Referer header only contains the domain name, and the Referer header is not sent when an HTTPS page requests an HTTP resource.
    • strict-origin-when-cross-origin: The Referer header contains the full path for same-origin requests, and only domain names for cross-origin requests.
    • This header is not sent when an HTTPS page requests an HTTP resource.
    • unsafe-url: Always send the Referer header no matter what.
fetch('http://localhost:3000/test',{
    
    
    method: 'post',
    headers: {
    
    
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
    
    
        name: 'qfc',
        age: 18
    })
}).then(res => {
    
    
    console.log(res)
})

image-20220624222137163

What needs to be noted is the body property of the Request object, which supports

  • Query parameter string, such as 'name=qfc&age=18'
  • A text string such as '{"name":"qfc", "age": 18}'
  • FormData object
  • Blob object
  • ReadableStream object
  • BufferSource object

2.3.2 Response

After the fetch request is successful, the response object is as shown in the figure:

image-20220624221326446

  • status - http status code, ranging from 100-599
  • statusText - the text description of the status returned by the server
  • ok - returns a boolean value, true if the status code starts with 2, otherwise false
  • headers - the response headers
  • body - the response body. The data in the response body is processed according to the type.
  • type - Returns the request type.
    • basic: Standard value, same-origin response, with all headers except "Set-Cookie" and "Set-Cookie2".
    • cors: Response A valid cross-origin request was received.
    • error: Network error. No useful information describing the error. The response has status 0, headers are empty and immutable. The type of response obtained from Response.error().
    • opaque: Respond to "no-cors" cross-origin requests.
    • redirected - Returns a boolean indicating whether the Response came from a redirect, if so, its URL list will have multiple entries.
  • url: HTTP request URL

Among them, we need to pay attention to the fact that the body attribute value is a readable stream, so we cannot directly obtain the content of the body, we need to read the content from the readable stream, and reading the content in the readable stream is also an asynchronous operation, Response considerate Provides us with the following instance methods to asynchronously obtain the content in the body readable stream

  • json() reads the body content as a JSON object
  • text() reads the body content as a normal text string
  • formData() reads the body content as a FormData object
  • blob() reads the body content as a Blob object
  • arrayBuffer() reads the body content as an ArrayBuffer object

The above methods all return a Promise object, and the result value of the Promise object is the data they read and converted into the corresponding format.

fetch('http://127.0.0.1:8000/fetch-server?vip=10', {
    
    
    //请求方法
    method: 'POST',
    //请求头
    headers: {
    
    
        name:'atguigu'
    },
    //请求体
    body: 'username=admin&password=admin'
}).then(response => {
    
    
    // return response.text();
    return response.json();
}).then(response=>{
    
    
    console.log(response);
});

Through the above code test, it is found that the result value of the Promise returned by response.json() is indeed the actual content of the body, and it is automatically converted into a JSON object.

2.4 GET and POST

2.1.1 GET

fetch(`http://localhost:80/fetch.html?user=${user.value}&pas=${pas.value}`,{
 method:'GET'
}).then(response=>{
 console.log('响应',response)
})

2.1.2 POST

fetch(`http://localhost:80/fetch`,{
    
    
 method:'POST',
 headers:{
    
    
  'Content-Type':'application/x-www-form-urlencoded;charset=UTF-8'
 },
 body:`user=${
      
      user.value}&pas=${
      
      pas.value}`
 }).then(response=>{
    
    
  console.log('响应',response)
})

If you are submitting json data, you need to convert json into a string. like

fetch(`http://localhost:80/fetch`,{
    
    
 method:'POST',
    headers: {
    
    
        'Content-Type': 'application/json'
    },
    body: JSON.stringify({
    
    
        name: 'qfc',
        age: 18
    }).then(response=>{
    
    
  console.log('响应',response)
})

If form data is submitted, use formData to convert it, such as:

body:new FormData(form)

Upload files can be included in the entire form and submitted together, such as:

const input = document.querySelector('input[type="file"]');

const data = new FormData();
data.append('file', input.files[0]);
data.append('user', 'foo');

fetch('/avatars', {
    
    
  method: 'POST',
  body: data
});

2.5 fetch does not carry cookies by default

When passing a cookie, it must be added in the parameter credentials:'include', so that the current cookie will be included in the request like xhr.

2.6 Exception handling

fetch is different from xhr, xhr has its own methods such as cancel and error, so when the server returns 4xx or 5xx, no error will be thrown, and it needs to be processed manually, which can be judged by the status field in the response.

3. Cross domain

3.1 Same Origin Policy

  • The Same-Origin Policy (Same-Origin Policy) was first proposed by Netscape and is a security policy for browsers.
  • Same origin: protocol, domain name, port number must be exactly the same
  • Cross-domain: Violation of the same-origin policy is cross-domain

3.2 How to solve cross domain

3.2.1 JSONP

jsonp only supports get requests but not post requests

1) What is JSONP

JSONP (JSON with Padding), is an unofficial cross-domain solution, developed purely with the ingenuity of programmers, and only supports get requests.

2) How does JSONP work?

Some tags on web pages are inherently capable of cross-domain, such as: img link iframe script. JSONP uses the cross-domain capabilities of script tags to send requests.

3) Use of JSONP

html code

//1. 创建 script 标签
const script = document.createElement('script');
//2. 设置标签的 src 属性
script.src = 'http://127.0.0.1:8000/check-username?callback=abc';
//3. 将script 添加到body 中
document.body.appendChild(script);
function abc(data) {
    
    
    alert(data.name);
};

backend code

app.get("/check-username" , function (req , res) {
    
    
    var callback = req.query.callback;
    const data = {
    
    
        name: '孙悟空'
    };
    //将数据转化为字符串
    let str = JSON.stringify(data);
    //返回结果(一段可执行的JavaScript代码)
    response.end(`handle(${
      
      str})`);
});

3.2.2 CORS

https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

  1. What is CORS? CORS (Cross-Origin Resource Sharing), cross-domain resource sharing. CORS is an official cross-domain solution. Its feature is that it does not require any special operations on the client side, and it is completely processed in the server, and it supports get and post requests. A new set of HTTP header fields has been added to the cross-origin resource sharing standard, allowing the server to declare which origin sites have permission to access which resources through the browser
  2. How does CORS work? CORS tells the browser by setting a response header that the request allows cross-domain, and the browser will release the response after receiving the response.
  3. The use of CORS is mainly server-side settings:
router.get("/testAJAX" , function (req , res) {
    
    
    //通过res 来设置响应头,来允许跨域请求
    //res.set("Access-Control-Allow-Origin","http://127.0.0.1:3000");
    res.set("Access-Control-Allow-Origin","*");//允许所有来源访问
    res.send("testAJAX 返回的响应");
});

Guess you like

Origin blog.csdn.net/m0_55644132/article/details/128349973