史上最全的前端axios和后端跨域配置處理
本小節(jié)內(nèi)容需要對(duì)vue前端框架以及對(duì)后端的基礎(chǔ)框架所有掌握哦!前后端項(xiàng)目分離中經(jīng)常會(huì)涉及到請(qǐng)求跨域的問題,今天讓我們一起來掌握它吧?。?!
安裝axios【https://www.axios-http.cn/】
npm install axios
封裝一個(gè)基本的請(qǐng)求js
創(chuàng)建remote.ts或者其他文件名
import axios from "axios";
const server = 'http://localhost:8181'
/**
* async 異步處理
* await 等待處理完成
*/
async function getData(url,param){
var ret = ''
await axios.get(server+url, {params: param}).then(function (res) {
ret = res.data
})
return ret
}
//post請(qǐng)求體傳輸數(shù)據(jù)
async function postData(url,param){
var options = { // 設(shè)置axios的參數(shù)
url: server+url,
data: param,
method: 'post',
}
var ret = ''
await axios(options).then(function (res) {
ret = res
})
return ret
}
//post表單形式提交 請(qǐng)求頭傳輸數(shù)據(jù)
async function postDataForm(url,param){
var options = { // 設(shè)置axios的參數(shù)
url: server+url,
data: param,
method: 'post',
headers: {'Content-Type':'application/x-www-form-urlencoded'}
}
var ret = ''
await axios(options).then(function (res) {
ret = res
})
return ret
}
async function uploadFile(url,param){
var options = { // 設(shè)置axios的參數(shù)
url: server+url,
data: param,
method: 'post',
headers: {
'Content-Type': 'multipart/form-data'
}
}
var ret = ''
await axios(options).then(function (res) {
ret = res.data
})
return ret
}
// export:導(dǎo)出變量、函數(shù)
export {getData,postData,postDataForm,uploadFile}
使用
import {getData,postData,uploadFile} from '../common/remote'
getData('/user/list',{current:current}).then(function (res) {
})
postData('/user/delete',[id]).then(function (res) {
})
uploadFile(url,formData).then(function (res) {
})
Vite 解決跨域問題
Access-Control-Allow-Origin
- 在寫代碼的時(shí)候出現(xiàn)上述跨域問題
解決問題
在工程文件夾的根目錄新建一個(gè)vite.config.js文件,寫入代碼:
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
server:{
proxy: {
'/api': {
target: 'http://localhost:8080/', //你要跨域訪問的網(wǎng)址
changeOrigin: true, // 允許跨域
rewrite: (path) => path.replace(/^\/api/, '') // 重寫路徑把路徑變成空字符
}
}
}
})
然后在需要發(fā)送請(qǐng)求的文件中寫,就可以跨域請(qǐng)求數(shù)據(jù)了:
var options = { // 設(shè)置axios的參數(shù)
url: '/api/login',
data: {username:username.value,password:password.value},
method: 'post',
headers: {'Content-Type':'application/x-www-form-urlencoded'}
}
axios(options).then((res: any)=>{
console.log(res);
if(res.data==='loginOK'){
router.push('/');
}else{
alert('賬號(hào)密碼錯(cuò)誤');
}
})
在vite.config.js文件中的’/api’ 可以改成任意你想要的名字,只要把它重寫成空字符,就無所謂的,還是原來的網(wǎng)址。
后端SpringBoot 相關(guān)的跨域處理
一、為什么會(huì)出現(xiàn)跨域問題
出于瀏覽器的同源策略限制。同源策略(Sameoriginpolicy)是一種約定,它是瀏覽器最核心也最基本的安全功能,如果缺少了同源策略,則瀏覽器的正常功能可能都會(huì)受到影響??梢哉fWeb是構(gòu)建在同源策略基礎(chǔ)之上的,瀏覽器只是針對(duì)同源策略的一種實(shí)現(xiàn)。
同源策略
同源策略會(huì)阻止一個(gè)域的javascript腳本和另外一個(gè)域的內(nèi)容進(jìn)行交互。所謂同源(即指在同一個(gè)域)就是兩個(gè)頁(yè)面具有相同的協(xié)議(protocol),主機(jī)(host)和端口號(hào)(port)
二、什么是跨域
舉例說明:
當(dāng)一個(gè)請(qǐng)求url的協(xié)議、域名、端口三者之間任意一個(gè)與當(dāng)前頁(yè)面url不同即為跨域
三、非同源限制
- 【1】無法讀取非同源網(wǎng)頁(yè)的 Cookie、LocalStorage 和 IndexedDB
- 【2】無法接觸非同源網(wǎng)頁(yè)的 DOM
- 【3】無法向非同源地址發(fā)送 AJAX 請(qǐng)求
四、java 后端 實(shí)現(xiàn) CORS 跨域請(qǐng)求的方式
對(duì)于 CORS的跨域請(qǐng)求,主要有以下幾種方式可供選擇:
- 1.返回新的CorsFilter
- 2.重寫 WebMvcConfigurer
- 3.使用注解 @CrossOrigin
- 4.手動(dòng)設(shè)置響應(yīng)頭 (HttpServletResponse)
- 5.自定web filter 實(shí)現(xiàn)跨域
注意
- CorFilter / WebMvConfigurer / @CrossOrigin 需要 SpringMVC 4.2以上版本才支持,對(duì)應(yīng)springBoot 1.3版本以上
- 上面前兩種方式屬于全局 CORS 配置,后兩種屬于局部 CORS配置。如果使用了局部跨域是會(huì)覆蓋全局跨域的規(guī)則,所以可以通過 @CrossOrigin 注解來進(jìn)行細(xì)粒度更高的跨域資源控制。
- 其實(shí)無論哪種方案,最終目的都是修改響應(yīng)頭,向響應(yīng)頭中添加瀏覽器所要求的數(shù)據(jù),進(jìn)而實(shí)現(xiàn)跨域
1.返回新的 CorsFilter(全局跨域)
在任意配置類,返回一個(gè) 新的 CorsFIlter Bean ,并添加映射路徑和具體的CORS配置路徑。
@Configuration
public class GlobalCorsConfig {
@Bean
public CorsFilter corsFilter() {
//1. 添加 CORS配置信息
CorsConfiguration config = new CorsConfiguration();
//放行哪些原始域
config.addAllowedOrigin("*");
//是否發(fā)送 Cookie
config.setAllowCredentials(true);
//放行哪些請(qǐng)求方式
config.addAllowedMethod("*");
//放行哪些原始請(qǐng)求頭部信息
config.addAllowedHeader("*");
//暴露哪些頭部信息
config.addExposedHeader("*");
//2. 添加映射路徑
UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
corsConfigurationSource.registerCorsConfiguration("/**",config);
//3. 返回新的CorsFilter
return new CorsFilter(corsConfigurationSource);
}
}
2. 重寫 WebMvcConfigurer(全局跨域)
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
//是否發(fā)送Cookie
.allowCredentials(true)
//放行哪些原始域
.allowedOriginPatterns("*")
.allowedMethods(new String[]{"GET", "POST", "PUT", "DELETE"})
.allowedHeaders("*")
.exposedHeaders("*");
}
}
3.使用注解 (局部跨域)
在控制器(類上)上使用注解 @CrossOrigin:,表示該類的所有方法允許跨域。
@RestController
@CrossOrigin(origins = "*")
public class HelloController {
@RequestMapping("/hello")
public String hello() {
return "hello world";
}
}
在方法上使用注解 @CrossOrigin:
@RequestMapping("/hello")
@CrossOrigin(origins = "*")
//@CrossOrigin(value = "http://localhost:8081") //指定具體ip允許跨域
public String hello() {
return "hello world";
}
4. 手動(dòng)設(shè)置響應(yīng)頭(局部跨域)
使用 HttpServletResponse 對(duì)象添加響應(yīng)頭(Access-Control-Allow-Origin)來授權(quán)原始域,這里
Origin的值也可以設(shè)置為 “*”,表示全部放行。
@RequestMapping("/index")
public String index(HttpServletResponse response) {
response.addHeader("Access-Allow-Control-Origin","*");
return "index";
}
5. 使用自定義filter實(shí)現(xiàn)跨域
SSM用法首先編寫一個(gè)過濾器,可以起名字為MyCorsFilter.java
package com.xuguoguo.aop;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
@Component
public class MyCorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "x-requested-with,content-type");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
在web.xml中配置這個(gè)過濾器,使其生效
<!-- 跨域訪問 START-->
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>com.mesnac.aop.MyCorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 跨域訪問 END -->
springboot可以簡(jiǎn)化
import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(filterName = "CorsFilter ")
@Configuration
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin","*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
chain.doFilter(req, res);
}
}
SpringBoot中使用
- DataGetRequestController
package com.xuguoguo.controller;
import com.xuguoguo.entity.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
public class DataGetRequestController {
@GetMapping("/getInt")
public int getInt(int id){
return id;
}
@GetMapping(value = "/getBox")
public String getBox(String name,Integer id){
return "name = " + name + " id = " + id;
}
@GetMapping("/getRequestParam")
public String getRequestParam(@RequestParam(value = "rp",required = false) Integer id){
return "ID = " + id;
}
@GetMapping(value = "/getUser")
public User getUser(User user){
return user;
}
@GetMapping("/getIds")
public List<Long> getIds(@RequestParam List<Long> ids){
return ids;
}
@GetMapping(value = "/getMap")
public Map<String,Object> getMap(@RequestParam Map<String,Object> map){
return map;
}
@GetMapping(value = "/getObj")
public Object getObj(@RequestParam(name = "ik",required = true,defaultValue = "500") Integer id){
return id;
}
@GetMapping("/getArr")
public String[] getArr(String[] arr){
return arr;
}
@GetMapping(value = "/getList")
public List<String> getList(@RequestParam List<String> names){
return names;
}
}
- DataPostRequestController
package com.xuguoguo.controller;
import com.xuguoguo.entity.User;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
@RestController
public class DataPostRequestController {
//表單形式接收
@PostMapping("/postInt")
public int postInt(int id){
return id;
}
//表單形式接收
@PostMapping("/postBox")
public String postBox(String name,Integer id){
return "name = " + name +" id = " + id;
}
/**
* @RequestBody:
* 要求請(qǐng)求參數(shù)必須是在body中的
*
* 如果不加@RequestBody:
* 請(qǐng)求可以放在parameter、body中
* 復(fù)雜對(duì)象也是可以傳的
* @param user
* @return
*/
@PostMapping("/postUser")
public User postUser(@RequestBody User user){
return user;
}
//表單形式接收
@PostMapping("/postUserNoBody")
public User postUserNoBody( User user){
return user;
}
@PostMapping("/postIds")
public List<Integer> postIds(@RequestBody List<Integer> ids){
return ids;
}
@PostMapping("/postUsers")
public List<User> postUsers(@RequestBody List<User> users){
return users;
}
@PostMapping("/postMap")
public Map<String,Object> postMap(@RequestBody Map<String,Object> map){
return map;
}
}
axios get請(qǐng)求
<script setup>
import {getData,postData,uploadFile} from './remote.ts'
getData('/getInt',{id:100}).then(function (res) {
console.log('getInt--->'+res)
})
getData('/getBox',{id:100,name:'張三'}).then(function (res) {
console.log('getBox--->'+res)
})
getData('/getRequestParam',{rp:100}).then(function (res) {
console.log('getRequestParam--->'+res)
})
getData('/getUser',{id:100,userName:'張三',password:'123456'}).then(function (res) {
console.log('getUser--->id:'+res.id+' userName:'+res.userName+' password:'+res.password)
})
getData('/getIds',{ids:'1,2,3,4,5'}).then(function (res) {
console.log('getIds--->'+res)
console.log('getIds--->'+res[3])
})
getData('/getMap',{id:100,userName:'張三',password:'123456'}).then(function (res) {
console.log('getMap--->id:'+res.id+' userName:'+res.userName+' password:'+res.password)
})
getData('/getArr',{arr:'張三,李四,王五'}).then(function (res) {
console.log('getArr--->'+res)
})
getData('/getList',{names:'張三,李四,王五'}).then(function (res) {
console.log('getList--->'+res)
})
</script>
<template>
</template>
axios post請(qǐng)求
<script setup>
import {getData,postData,postDataForm,uploadFile} from './remote.ts'
postDataForm('/postInt',{id:100}).then(function (res) {
console.log(res)
console.log('postInt--->'+res.data)
})
postDataForm('/postBox',{id:100,name:'李四'}).then(function (res) {
console.log(res)
console.log('postBox--->'+res.data)
})
postData('/postUser',{id:100,userName:'李四',password:'123456'}).then(function (res) {
console.log(res)
console.log('postUser--->id:'+res.data.id+' userName:'+res.data.userName+' password:'+res.data.password)
})
postDataForm('/postUserNoBody',{id:100,userName:'李四',password:'123456'}).then(function (res) {
console.log(res)
console.log('postUserNoBody--->id:'+res.data.id+' userName:'+res.data.userName+' password:'+res.data.password)
})
postData('/postIds',[1,2,3,4,5]).then(function (res) {
console.log(res)
console.log('postIds--->'+res)
})
postData('/postUsers',[{id:100,userName:'李四',password:'123456'},{id:101,userName:'王五',password:'123456'}]).then(function (res) {
console.log('----postUsers----')
console.log(res)
console.log('----postUsers----')
})
postData('/postMap',{id:100,userName:'李四',password:'123456'}).then(function (res) {
console.log('----postMap----')
console.log(res)
console.log('----postMap----')
})
</script>
<template>
</template>
小結(jié)
提示:本小節(jié)主要寫的是基于前后端分離項(xiàng)目中的跨域請(qǐng)求的不同處理處理方式,前端的處理以及后臺(tái)的處理,學(xué)起來以防遇到此類問題的時(shí)候不知道如何解決哦?。。?/code>
**多學(xué)一招,偷偷的努力,然后驚艷所有人?。。【砭屯炅恕?/s> **
本小節(jié)完畢,敬請(qǐng)期待后續(xù)更新(可留言需要學(xué)習(xí)哪方面的內(nèi)容哈)!如果需要源碼或者工具的朋友們可關(guān)注微信公眾號(hào)"鍋鍋編程生活"或者掃描二維碼關(guān)注回復(fù)關(guān)鍵字/后臺(tái)留言獲取即可!文章來源:http://www.zghlxwxcb.cn/news/detail-806032.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-806032.html
到了這里,關(guān)于史上最全的前端axios和后端跨域配置處理-許鍋鍋啊的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!