背景
我们web前端在开发过程中。有的时候,遇到如下的跨域报警时,要么后端做一些措施,解决跨域的问题,比如(加cors请求头)。如果后端没有及时响应,这个时候就需要我们前端自己来解决跨域的问题。而反向代理就是我们web前端常用的解决跨域问题的有效手段之一。本次我们以vue框架为例,进行示范和记录反向代理的配置流程。
Access to XMLHttpRequest at *** from origin
配置反向代理(vue2.0)
1.配置请求中间件axios
src/utils/request.js
import axios from "axios";
const service = axios.create({
//这里的api对应proxy 配置的api
baseURL: "/api",
timeout: 3000, // 请求响应的时间
});
service.interceptors.request.use(
(config) => {
// 在发送请求之前做些什么
//...
return config;
},
(error) => {
console.log(error);
return Promise.reject(error);
}
);
service.interceptors.response.use(
(response) => {
// 对响应数据做点什么
//...
return response;
},
(error) => {
console.log(error);
return Promise.reject(error);
}
)
export default service
2.配置vue.config.js
vue.config.js
module.exports = {
/*...
...其他配置项
...*/
devServer: {
host: "0.0.0.0", // 允许外部ip访问
port: 8080, // 自定义修改8080端口
https: false, // 启用https
open: true, //build自动打开浏览器
proxy: {
// 下面的api是监听你请求的接口是否存在api;如存在,会开启反向代理
"/api": {
target: "http://192.168.1.0:8000", //代理地址(目标服务器)
/*如果接口跨域,需要配置changeOrigin;开启时在本地会创建一个虚拟服务端,然后发送请求的
数据,并同时接收请求的数据,这样服务端和服务端进行数据的交互就不会有跨域问题*/
changeOrigin: true,
//pathRewrite方法重写url
pathRewrite: {
"^/api": "/",
},
//pathRewrite: {'^/api': '/'} 重写之后url为 http://192.168.1.0:8000/xxxx
//pathRewrite: {'^/api': '/api'} 重写之后url为 http://192.168.1.0:8000/api/xxxx
},
},
},
};
这段代码的作用是将所有以/api
开头的请求转发到http://192.168.1.0:8000。这意味着当你在前端代码中发起一个HTTP请求时,例如axios.get('/api
/data')
,实际请求会被发送到http://192.168.1.0:8000/data。这样的配置使得前后端可以分别运行在不同的服务器上,同时避免了跨域问题。
配置细节
- target: 指定要代理的目标URL。
- changeOrigin: 设置为
true
时,会修改请求头中的Host字段为目标服务器的域名,这有助于某些后端服务正确处理请求。 - rewrite: 使用正则表达式替换请求路径的一部分。比如,上面的例子中,任何以
/api
开头的路径都会被替换为空字符串,即去掉/api
前缀后再发送给目标服务器
3.使用请求中间件调用后端api接口
@/api/login.js
import request from "@/utils/request";
// 请求登录接口
export const login = (data) =>
request({
url: "/login",
method: "POST",
data,
});
4.业务使用接口
login.vue
<script>
import { login } from '@/api/login.js'
export default {
data () {
return {
form: {
//...
}
}
},
methods: {
async login() {
await login(this.form)
}
}
}
</script>
反向代理的配置到这里就结束了,那么你学会了嘛~
配置反向代理(vue3.0)
上面的第二步,配置vue.config.js,在vue3里是在vite.config.js里进行配置,其他的步骤同上。
配置vite.config.js
import { fileURLToPath, URL } from "node:url";
import { defineConfig } from "vite";
import vue from "@vitejs/plugin-vue";
// https://vitejs.dev/config/
export default defineConfig({
base: "/", // 设置项目的基础路径
// 设置服务器配置
server: {
open: true,// 自动打开浏览器
hmr: true,// 启用热模块替换
// 设置反向代理
proxy: {
// 代理/api路径
'/api': {
target: 'http://192.168.1.0:8000',// 设置目标服务器地址
changeOrigin: true,// 改变源地址(开启反向代理)
rewrite: path => path.replace(/^\/api/, ''),// 重写路径
},
}
},
plugins: [vue()],// 设置插件
// 设置路径别名
resolve: {
alias: {
// 设置@为src目录
"@": fileURLToPath(new URL("./src", import.meta.url)),
},
},
});
拓展
浏览器为什么会有同源策略
浏览器之所以会有同源策略(Same-Origin Policy, SOP),主要是出于安全考虑。这个策略限制了一个源的文档或脚本如何与另一个源的资源进行交互,从而防止恶意网站通过脚本访问其他网站的敏感信息或执行恶意操作。
具体来说,同源策略是基于URL的协议、主机和端口来定义的。如果两个URL的这三个部分都相同,则认为它们是同源的;否则,就认为是非同源的。例如,http://store.company.com/dir/page.html
和 http://store.company.com/dir2/other.html
是同源的,因为它们的协议、主机和端口都相同,而 http://store.company.com:81/dir/etc.html
由于端口不同则被认为是不同的源。
同源策略的存在是为了保护用户的隐私和数据安全。它确保了来自不同源的网页之间不能随意互相读取或修改对方的内容,比如阻止一个网站上的JavaScript代码读取另一个网站上的Cookie或其他敏感信息。此外,同源策略也防止了跨站脚本攻击(XSS)和其他类型的网络攻击。
想象一下,如果没有同源策略,那么当你登录到银行网站A之后再访问另一个网站B时,B网站可能会尝试使用你的身份去请求A网站的数据。由于你已经在A网站上登录过,因此这些请求会附带有效的认证信息(如Cookies),这将使得B网站能够获取到原本只有你自己能访问的信息,进而导致严重的安全隐患
为了应对实际开发中遇到的不同源之间的合法通信需求,Web开发者们提出了几种方法来安全地实现跨域资源共享:
CORS (Cross-Origin Resource Sharing):服务器可以通过设置HTTP响应头中的特定字段来允许某些特定来源的请求。这是一种标准的方法,允许细粒度地控制哪些站点可以访问资源。
JSONP (JSON with Padding):利用
<script>
标签不受同源策略限制的特点,通过动态加载外部脚本来获取数据,并在回调函数中处理返回的数据。不过这种方法现在用得较少,因为它只支持GET请求并且存在一定的安全风险。PostMessage API:提供了一种安全的方式让不同源的窗口之间传递消息。它允许父窗口与嵌入的iframe之间互相发送信息,同时保证了通信的安全性。
WebSocket:虽然WebSocket连接本身不受同源策略的影响,但建立连接时仍然需要遵循一定的规则以确保安全性。
总之,同源策略作为浏览器最核心也最基本的安全功能之一,对于维护互联网的安全性和用户信任至关重要。它不仅保障了用户个人信息的安全,也为整个Web生态系统的健康发展提供了坚实的基础。
为什么项目上线后不推荐继续使用反向代理
项目上线后不推荐继续使用开发环境中的反向代理配置,如`devServer.proxy`,主要是因为这些配置是专门为开发阶段设计的,旨在简化开发过程中的跨域问题。然而,当应用程序部署到生产环境中时,直接依赖于开发环境的代理设置可能会带来一系列的问题和挑战。
1. 开发与生产环境差异
开发环境下的反向代理配置通常是通过前端构建工具(例如Vue CLI)提供的功能实现的,它允许开发者在本地运行的应用程序中轻松地将API请求转发给后端服务。但是一旦应用被打包并部署到生产环境中,这种基于前端工具链的代理机制就不再适用了。打包后的静态资源文件并不包含任何关于如何处理网络请求的信息,因此无法像开发模式那样自动进行请求转发。
2. 生产环境的安全性要求
生产环境中对安全性的要求更高。使用Nginx等Web服务器作为反向代理不仅能够有效地解决跨域问题,还能提供额外的安全层,比如隐藏真实服务器IP地址、过滤恶意流量以及实施更严格的访问控制策略。此外,专业的Web服务器可以更好地管理SSL证书,确保HTTPS连接的安全性。
3. 性能考虑
相比于简单的开发工具提供的代理功能,专业级的Web服务器如Nginx经过优化以处理高并发请求,并且具有更低的延迟和更高的吞吐量。它们还支持缓存静态资源、压缩响应内容等功能,有助于提高网站的整体性能。相比之下,如果继续使用开发环境中的代理配置,则可能需要额外的服务或中间件来完成类似的任务,这会增加系统的复杂性和潜在的故障点。
4. 可维护性和扩展性
随着项目的成长和技术栈的变化,保持一个清晰且易于维护的架构变得尤为重要。通过将反向代理逻辑移到Web服务器层面,可以更容易地管理和调整路由规则,而不需要修改应用程序代码本身。这对于大型团队协作特别有利,因为它减少了不同成员之间沟通的成本,并使得未来的技术升级更加平滑。
5. 环境一致性
为了保证从开发到生产的顺利过渡,尽量让两个环境尽可能相似是非常重要的。这意味着应该避免在不同的环境中采用完全不同的解决方案。通过统一使用Nginx或其他类似的Web服务器来进行反向代理,可以在所有环境中提供一致的行为,减少因环境差异导致的问题。
综上所述,在项目上线之后,推荐使用专业的Web服务器(如Nginx)来代替开发环境中的简单代理配置。这样做不仅可以增强系统的安全性、提升性能,还能简化运维工作,确保整个系统的稳定性和可扩展性。
正向代理和反向代理的区别
正向代理(Forward Proxy)和反向代理(Reverse Proxy)是两种不同类型的网络代理服务器,它们的主要区别在于服务的对象和数据流的方向。
正向代理 (Forward Proxy)
- 服务对象:正向代理主要服务于客户端。它作为客户端的代表去访问互联网上的资源。对于客户端来说,它是通往外界的一个出口。
- 数据流向:客户端 -> 正向代理 -> 服务器
- 用途:
- 客户端可以通过正向代理来隐藏自己的真实IP地址。
- 可以用于绕过某些地理限制或内容过滤。
- 组织内部可以使用正向代理来控制和监控员工对外网的访问。
- 配置要求:需要在每个客户端上配置代理设置,指明要通过哪个代理服务器访问外部网络。
反向代理 (Reverse Proxy)
- 服务对象:反向代理主要是为服务器提供服务。它接收来自外部的请求,并将这些请求转发给后端的服务器,然后再把服务器响应返回给客户端。
- 数据流向:客户端 -> 反向代理 -> 服务器
- 用途:
- 负载均衡:分发流量到多个服务器,提高网站性能。
- 提供缓存功能,减少对源服务器的压力。
- 增强安全性:隐藏后端服务器的真实IP地址,防止直接暴露于公网中。
- SSL终止:处理HTTPS加密解密工作,减轻应用服务器负担。
- 静态内容服务:直接从反向代理服务器提供静态文件,如图片、CSS等。
- 配置要求:一般不需要客户端做任何特别的配置,因为客户端认为自己是在直接与最终的服务端进行通信。
简而言之,正向代理帮助客户端获取资源并保护客户端的身份;而反向代理则帮助服务器管理进入的请求并保护服务器的身份。两者都可以用来优化网络性能、增加安全性和简化管理。
正向代理 客户端一侧 客户端访问外网的中介(如翻墙)
反向代理 服务器一侧 保护、负载均衡、缓存、路径重写
在正向代理中,客户端隐藏自己;而在反向代理中,服务器隐藏自己。
后端java如何通过CORS解决跨域问题
在Java应用程序中,尤其是基于Servlet的应用程序如Spring Boot或传统的Java EE应用,可以通过多种方式来处理CORS(跨域资源共享)问题。以下是几种常见的解决方案:
1. 使用过滤器(Filter)
你可以创建一个自定义的过滤器,在每个请求到达你的资源之前添加必要的CORS响应头。以下是一个简单的例子:
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.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CorsFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) res;
HttpServletRequest request = (HttpServletRequest) req;
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, authorization");
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
} else {
chain.doFilter(req, res);
}
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
然后你需要将这个过滤器注册到你的web应用中。
2. 在Spring框架中使用@CrossOrigin
注解
如果你使用的是Spring框架,那么可以使用@CrossOrigin
注解来简化配置。你可以在控制器类或者方法上直接添加此注解:
@CrossOrigin(origins = "http://example.com")
@RestController
@RequestMapping("/api")
public class MyController {
// ...
}
这会自动为该控制器中的所有方法或特定方法添加CORS支持。
3. 配置全局CORS设置
对于更复杂的场景,比如需要对不同的路径设置不同的CORS规则,你可以通过配置全局CORS设置来实现。在Spring Boot中,你可以通过重写WebMvcConfigurer
接口的方法来完成:
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://example.com")
.allowedMethods("PUT", "DELETE")
.allowedHeaders("header1", "header2", "header3")
.exposedHeaders("header1", "header2")
.allowCredentials(true).maxAge(3600);
}
}
以上是解决Java应用程序中CORS问题的一些基本方法。根据你的具体需求和使用的框架版本,选择最适合的方式来配置CORS。