温馨提示:这篇文章已超过378天没有更新,请注意相关的内容是否还可用!
摘要:,,本文旨在通过图文并茂的方式,介绍如何模拟处理HTTP接口中的302状态码,并实现在JavaScript中的axios和fetch库遇到302状态码后的跳转。文章详细解释了通过axios和fetch成功响应拦截302状态码的多种方案,帮助开发者在遇到此类情况时能够迅速有效地解决问题。
前情提要
- 日常工作中,我们会使用fetch,或者axios发起请求来获取数据,但是当我们遇到一些特殊需求的时候,使用不同库之后,会得到不同的结果,例如302,308的状态码,那么我们应该怎么处理这两种情况呢?
下面我将会手把手教你实现:
- 如何使用多种方案实现前端代码+302后端接口实现页面跳转?
- fetch 发送GET 或者 POST请求如何处理 302?或者是说fetch 怎么才能拦截302?
- Axios 响应拦截 302 状态码的方案有哪些?如何实现?
基础环境准备
使用简单代码启动一个简单的nodejs后端
初始化项目
npm init
安装依赖
npm install express cors --save
模拟几个302请求
根目录下创建app.js文件,我们模拟一些302请求
var express = require("express"); var app = express(); const cors = require("cors"); //跨域请求cors app.use( cors({ origin: "*", credentials: true, }) ); // code 200 请求 app.get("/success", function (req, res) { res.send("ok"); }); app.post("/success", function (req, res) { res.send("ok"); }); // code 500 请求 app.get("/error500", function (req, res) { res.sendStatus(500); }); const urlInfo = { baidu: "https://www.baidu.com/", error: "http://localhost:3002/error500", // 这个接口会返回状态码500 notFound: "http://localhost:3002/notfound", // 根本就没有这个接口 success: "http://localhost:3002/success", // 200 }; app.get("/redirect-success", function (req, res) { res.redirect(302, urlInfo.success); }); app.post("/redirect-success", function (req, res) { res.redirect(302, urlInfo.success); }); app.get("/redirect-baidu", function (req, res) { res.redirect(302, urlInfo.baidu); }); app.post("/redirect-baidu", function (req, res) { res.redirect(302, urlInfo.baidu); }); app.get("/redirect-error", function (req, res) { res.redirect(302, urlInfo.error); }); app.post("/redirect-error", function (req, res) { res.redirect(302, urlInfo.error); }); app.get("/redirect-not-found", function (req, res) { res.redirect(302, urlInfo.notFound); }); app.post("/redirect-not-found", function (req, res) { res.redirect(302, urlInfo.notFound); }); var http = app.listen(3002, "127.0.0.1", function () { var httpInfo = http.address(); console.log(`创建服务${httpInfo.address}:${httpInfo.port}成功`); });
注意事项
- 下述状态码,我只试了302,大家可以自行修改后端代码测试其他状况哦~~
重定向状态码:
301: Moved Permanently
302: Found
303: See Other
307: Temporary Redirect
308: Permanent Redirect
启动http服务
node app.js
或者是使用supervisor来进行服务端代码热更新
supervisor使用方式(建议使用它来启动代码)
- npm官方文档
- Node Supervisor用于在程序崩溃时重新启动程序。
- 它还可以用于在*.js文件更改时重新启动程序。
npm install supervisor -g supervisor app.js
启动成功
接口测试
前端准备
我这里用vue来举例子啦~~,其他框架都一样哦~~
创建项目
npm create vue@latest
下载依赖
cd 项目名 npm install
启动项目
npm run dev
准备基础页面
测试 .main { display: flex; align-items: center; justify-items: center; flex-wrap: wrap; flex-direction: column; margin-top: 20px; } button { font-size: 16px; display: block; margin-bottom: 15px; cursor: pointer; border: none; color: hsla(160, 100%, 37%, 1); padding: 10px; width: 300px; }
功能1:如何使用前端代码+302后端接口实现页面跳转?
方案1 - window.location.assign(当前页跳转)
我们在项目中添加以下代码
const urlInfo = { baidu: 'http://localhost:3002/redirect-baidu' } const toBaidu = () => { console.log(1) window.location.assign(urlInfo.baidu) } 点击此处跳转百度
方案2 - window.open(新页面打开,或者当前页打开,可以自己控制参数)
核心代码如下:(详细代码将会在后面全部粘贴出来)
window.open(urlInfo.baidu, '_blank');
方案3 - window.location.href
核心代码如下:(详细代码将会在后面全部粘贴出来)
window.open(urlInfo.baidu, '_blank');
功能1总体代码
const urlInfo = { baidu: 'http://localhost:3002/redirect-baidu' } const toBaidu1 = () => { window.location.assign(urlInfo.baidu) } const toBaidu2 = () => { window.open(urlInfo.baidu, '_blank'); } const toBaidu3 = () => { window.location.href = urlInfo.baidu } 点击此处跳转百度-1 点击此处跳转百度-2 点击此处跳转百度-3 .main { display: flex; align-items: center; justify-items: center; flex-wrap: wrap; flex-direction: column; margin-top: 20px; } button { font-size: 16px; display: block; margin-bottom: 15px; cursor: pointer; border: none; color: hsla(160, 100%, 37%, 1); padding: 10px; width: 300px; }
功能2:fetch 发送GET 或者 POST请求如何处理 302?或者是说fetch 怎么才能拦截302?
我们使用模拟的几个url来进行几种情况的展示,然后根据返回结果,大家就知道如何处理302情况了哦`
情况1:
const urlInfo = { baidu: 'http://localhost:3002/redirect-baidu', error: 'http://localhost:3002/redirect-error', notFound: 'http://localhost:3002/redirect-not-found', } const currentUrl = urlInfo.baidu const fetchGet = () => { fetch(currentUrl).then(_ =>{ console.log('fetch get ---then--- current url:', currentUrl) console.log(_) }).catch(e=>{ console.log('fetch get ---catch--- current url:', currentUrl) console.log(e) }) } const fetchPost = () => { fetch(currentUrl,{method:'post'}).then(_ =>{ console.log('fetch post ---then--- current url:', currentUrl) console.log(_) }).catch(e=>{ console.log('fetch post ---catch--- current url:', currentUrl) console.log(e) }) } Fetch-Get-302 Fetch-Post-302 .main { display: flex; align-items: center; justify-items: center; flex-wrap: wrap; flex-direction: column; margin-top: 20px; } button { font-size: 16px; display: block; margin-bottom: 15px; cursor: pointer; border: none; color: hsla(160, 100%, 37%, 1); padding: 10px; width: 300px; }
情况2:
切换URL
const urlInfo = { baidu: 'http://localhost:3002/redirect-baidu', error: 'http://localhost:3002/redirect-error', notFound: 'http://localhost:3002/redirect-not-found', } const currentUrl = urlInfo.error const fetchGet = () => { fetch(currentUrl).then(_ =>{ console.log('fetch get ---then--- current url:', currentUrl) console.log(_) }).catch(e=>{ console.log('fetch get ---catch--- current url:', currentUrl) console.log(e) }) } const fetchPost = () => { fetch(currentUrl,{method:'post'}).then(_ =>{ console.log('fetch post ---then--- current url:', currentUrl) console.log(_) }).catch(e=>{ console.log('fetch post ---catch--- current url:', currentUrl) console.log(e) }) } Fetch-Get-302 Fetch-Post-302 .main { display: flex; align-items: center; justify-items: center; flex-wrap: wrap; flex-direction: column; margin-top: 20px; } button { font-size: 16px; display: block; margin-bottom: 15px; cursor: pointer; border: none; color: hsla(160, 100%, 37%, 1); padding: 10px; width: 300px; }
我们来分析一下这种情况,302重定向的URL是返回500的url,此时我们可以得到重定向后的结果,这个时候我们就有办法处理啦~
情况3:
切换URL
const urlInfo = { baidu: 'http://localhost:3002/redirect-baidu', error: 'http://localhost:3002/redirect-error', notFound: 'http://localhost:3002/redirect-not-found', } const currentUrl = urlInfo.notFound const fetchGet = () => { fetch(currentUrl).then(_ =>{ console.log('fetch get ---then--- current url:', currentUrl) console.log(_) }).catch(e=>{ console.log('fetch get ---catch--- current url:', currentUrl) console.log(e) }) } const fetchPost = () => { fetch(currentUrl,{method:'post'}).then(_ =>{ console.log('fetch post ---then--- current url:', currentUrl) console.log(_) }).catch(e=>{ console.log('fetch post ---catch--- current url:', currentUrl) console.log(e) }) } Fetch-Get-302 Fetch-Post-302 .main { display: flex; align-items: center; justify-items: center; flex-wrap: wrap; flex-direction: column; margin-top: 20px; } button { font-size: 16px; display: block; margin-bottom: 15px; cursor: pointer; border: none; color: hsla(160, 100%, 37%, 1); padding: 10px; width: 300px; }
情况4:
更改URL为200情况
const urlInfo = { baidu: 'http://localhost:3002/redirect-baidu', error: 'http://localhost:3002/redirect-error', notFound: 'http://localhost:3002/redirect-not-found', success: 'http://localhost:3002/redirect-success', } const currentUrl = urlInfo.success
总结
- 使用Fetch,302重定向的目标URL跨域的情况下,我们无法获取此时的请求具体信息,只能在catch里拿到报错结果
- 使用Fetch, 302重定向的目标URL返回状态码200,404,500的情况下,我们可以通过res.redirected准确得知此时接口是重定向,以及通过后端接口返回的res.url得到准确的重定向URL
- 综上所述,重定向目标URL正常的情况下,我们使用Fetch可以成功响应拦截 302 状态码,以及做后续的逻辑处理,因为cors的情况非常容易处理,使用代理等其他配置完全可以避免此种情况。
功能3:axios 发送GET 或者 POST请求如何处理 302?Axios 响应拦截 302 状态码的方案有哪些?如何实现?
下载依赖
npm i axios --save
编写基础代码
import axios from 'axios'; const urlInfo = { success: 'http://localhost:3002/redirect-success', baidu: 'http://localhost:3002/redirect-baidu', error: 'http://localhost:3002/redirect-error', notFound: 'http://localhost:3002/redirect-not-found', } const currentUrl = urlInfo.success const axiosGet = () => { axios.get(currentUrl).then(_ =>{ console.log('axios get ---then--- current url:', currentUrl) console.log(_) }).catch(e=>{ console.log('axios get ---catch--- current url:', currentUrl) console.log(e) }) } const axiosPost = () => { axios.post(currentUrl,{method:'post'}).then(_ =>{ console.log('axios post ---then--- current url:', currentUrl) console.log(_) }).catch(e=>{ console.log('axios post ---catch--- current url:', currentUrl) console.log(e) }) } Axios-Get-302 Axios-Post-302 .main { display: flex; align-items: center; justify-items: center; flex-wrap: wrap; flex-direction: column; margin-top: 20px; } button { font-size: 16px; display: block; margin-bottom: 15px; cursor: pointer; border: none; color: hsla(160, 100%, 37%, 1); padding: 10px; width: 300px; }
情况1:
const currentUrl = urlInfo.success
情况2:
跨域的情况下,会走catch,然后得到Network Error的报错提示语
{ "message": "Network Error", "name": "AxiosError", "stack": "AxiosError: Network Error\n at XMLHttpRequest.handleError (http://localhost:5173/node_modules/.vite/deps/axios.js?v=e7c1b0b9:1451:14)", "config": { "transitional": { "silentJSONParsing": true, "forcedJSONParsing": true, "clarifyTimeoutError": false }, "adapter": [ "xhr", "http" ], "transformRequest": [ null ], "transformResponse": [ null ], "timeout": 0, "xsrfCookieName": "XSRF-TOKEN", "xsrfHeaderName": "X-XSRF-TOKEN", "maxContentLength": -1, "maxBodyLength": -1, "env": {}, "headers": { "Accept": "application/json, text/plain, */*" }, "method": "get", "url": "http://localhost:3002/redirect-baidu" }, "code": "ERR_NETWORK", "status": null }
情况3:
情况4:
结论
我们打印一下统一的返回数据
{ "message": "Request failed with status code 500", "name": "AxiosError", "stack": "AxiosError: Request failed with status code 500\n at settle (http://localhost:5173/node_modules/.vite/deps/axios.js?v=e7c1b0b9:1204:12)\n at XMLHttpRequest.onloadend (http://localhost:5173/node_modules/.vite/deps/axios.js?v=e7c1b0b9:1421:7)", "config": { "transitional": { "silentJSONParsing": true, "forcedJSONParsing": true, "clarifyTimeoutError": false }, "adapter": [ "xhr", "http" ], "transformRequest": [ null ], "transformResponse": [ null ], "timeout": 0, "xsrfCookieName": "XSRF-TOKEN", "xsrfHeaderName": "X-XSRF-TOKEN", "maxContentLength": -1, "maxBodyLength": -1, "env": {}, "headers": { "Accept": "application/json, text/plain, */*", "Content-Type": "application/json" }, "method": "post", "url": "http://localhost:3002/redirect-error", "data": "{\"method\":\"post\"}" }, "code": "ERR_BAD_RESPONSE", "status": 500 }
- 使用Axios,302重定向的目标URL跨域的情况下,我们无法获取此时的请求具体信息,只能在catch里拿到报错结果,报错显示信息
- 使用Axios, 302重定向的目标URL返回状态码200的情况下,我们可以通过res.request.responseURL与res.config.url进行比对来准确得知此时接口是否重定向,以及通过后端接口返回的res.request.responseURL,以及如果重定向的url是html页面的话,我们加上判断headers[“content-type”]类型是否包含text/html得到准确的重定向URL
- 使用Axios, 302重定向的目标URL返回状态码404,500的情况下,我们可以通过catch 里 捕获 error.request.responseURL与error.config.url进行比对来准确得知此时接口是否重定向,以及通过后端接口返回的error.request.responseURL,以及如果重定向的url是html页面的话,我们加上判断headers[“content-type”]类型是否包含text/html得到准确的重定向URL
- 综上所述,重定向目标URL正常的情况下,我们使用Axios可以成功响应拦截 302 状态码,以及做后续的逻辑处理,因为cors的情况非常容易处理,使用代理等其他配置完全可以避免此种情况。
分析图示
代码
import axios from 'axios'; const urlInfo = { success: 'http://localhost:3002/redirect-success', baidu: 'http://localhost:3002/redirect-baidu', error: 'http://localhost:3002/redirect-error', notFound: 'http://localhost:3002/redirect-not-found', } const currentUrl = urlInfo.success const consoleLog = (_, type) => { // 请注意下面仅限于重定向和原有url不会包含关系 if(_.request.responseURL && _.request.responseURL.indexOf(_.config.url) === -1) { console.log(`------------------${type} --- 拦截302 ${_.config.method} 请求------------------`) console.log('请求URL:', _.config.url) console.log('重定向URL:', _.request.responseURL) } // 如果重定向的url是html页面的话,我们还可以加上判断headers["content-type"]类型是否包含text/html } const axiosGet = (url) => { axios.get(url).then(_ => { consoleLog(_, 'Then') }).catch(e => { consoleLog(e, 'Error') }) } const axiosPost = (url) => { axios.post(url, { method: 'post' }).then(_ => { consoleLog(_, 'Then') }).catch(e => { consoleLog(e, 'Error') }) } Axios-Get-302-success Axios-Post-302-success Axios-Get-302-baidu Axios-Post-302-baidu Axios-Get-302-error Axios-Post-302-error Axios-Get-302-notFound Axios-Post-302-notFound .main { display: flex; align-items: center; justify-items: center; flex-wrap: wrap; flex-direction: column; margin-top: 20px; } button { font-size: 16px; display: block; margin-bottom: 15px; cursor: pointer; border: none; color: hsla(160, 100%, 37%, 1); padding: 10px; width: 300px; }
代码仓库
今天就写到这里啦~
- 小伙伴们,( ̄ω ̄( ̄ω ̄〃 ( ̄ω ̄〃)ゝ我们明天再见啦~~
- 大家要天天开心哦
欢迎大家指出文章需要改正之处~
学无止境,合作共赢
欢迎路过的小哥哥小姐姐们提出更好的意见哇~~
- 下述状态码,我只试了302,大家可以自行修改后端代码测试其他状况哦~~
还没有评论,来说两句吧...