通过nginx配置解决前端跨域问题

一、什么是跨域

1. 同源策略

同源策略是浏览器中的一种安全机制,用于阻止恶意代码窃取数据或者执行一些危险操作,简单来说就是同协议,同域名,同端口,三者缺一不可。

2.跨域的情景

跨域指的是在浏览器发送请求时,请求的服务器URL与当前页面的域名不一致,即不满足同源策略。比如:

前端网址:http://localhost:8000。
服务器URL:http://localhost:8001。

当该端口的网站8000尝试访问服务器端接口时,由于端口不通,就会触发跨域。

3.跨域的原因

跨域问题主要是由浏览器中的安全机制:同源策略(same-origin policy) 引起的,这是浏览器为了用户安全而设计的一个重要机制。能够阻止恶意网站通过JavaScript访问另一个域的敏感数据或执行潜在的恶意操作。

因此当服务器请求和当前域名不同源时,浏览器会拦截客户端发出的请求回来的数据接收,即请求发送了,服务器响应了,但是无法被浏览器接收。

4.浏览器原理

每当发起访问时,浏览器在背后都会校验前端应用和服务端是否同源,源是由一系列属性构成的,包括网络传输协议,主机名称,端口等等。比如,
https://www.facebook-clone.com的传输协议是https,主机名称是www.facebook-clone.com
,端口是443(这里被隐藏了,https协议的默认访问端口是443)。

为了验证同源,浏览器会在所有请求中附带一个特殊的请求一起发送给域信息接收服务器。比如有个应用运行在域localhost:3000上,这个特殊请求的格式将像下面这样:

Origin: http://localhost:3000

作为回应,服务器返回的response会附带一个包含键为 Access-Control-Allow-Origin 的 header,用来标示什么样的源可以访问服务器的资源。该键可以对应两种值:

第一种,严格模式,只有一个指定的源可以获得权限访问:

Access-Control-Allow-Origin: http://localhost:3000

第二种,宽松模式,服务端允许任何源访问自己的资源:

Access-Control-Allow-Origin: *

浏览器接收到该响应后,会把前端应用的域和服务器返回的Access-Control-Allow-Origin值比较,如果比较不匹配,那么此次访问就被报错了,并且会返回一个CORS错误的提示。

二、跨域的解决方案

解决跨域问题有多种方法,如JSONP、CORS、Nginx代理等。

1.前后端结合(JsonP)

虽然jsonp也可以实现跨域,但是因为jsonp不支持post请求,应用场景受到很大限制,所以不考虑。

2.后端配置(跨域资源共享(CORS))

跨域资源共享即开放跨域请求,CORS 是w3c标准的方式,服务器默认是不被允许跨域的,可以通过给Nginx服务器配置Access-Control-Allow-Origin *,表示服务器可以接受所有的请求源(Origin),即接受所有跨域的请求。

在实际的浏览器发送请求中,如果浏览器检测到跨域,它会尝试发起一次请求,然后查看返回的内容中,是否一个有允许跨域请求的标记(CORS响应头),如果有正确的标记,那么就不拦截;如果没有标记,浏览器就会阻止这个请求,并报错。

同源策略只存在浏览器端,通过服务器转发请求可以达到跨域请求的目的,但是会增加服务器的负担,且访问速度慢。

3.Nginx配置代理请求的CORS

通过Nginx代理可以将跨域变成同源。首先要明白,是谁把前台向后台的请求拦截下来的?不是后台,而是浏览器。如果要避免跨域,只要让浏览器认为“我正在向同一个域发起请求”,就可以了。

在前端的代码中,可以在服务器的请求URL前加个特殊前缀,比如加一个/api/作为前缀,然后再nginx的配置中识别到/api/这个前缀就转发到服务器实际的地址中。

server {
    listen       80;
    server_name  localhost;

    location /api/ {
        proxy_pass   http://localhost:8001/;
    }

    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;

        try_files $uri $uri/ /index.html;
        expires 60s;
    }

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
         root   /usr/share/nginx/html; 
     }
}

一般情况下浏览器访问时是只显示客户端的访问地址,而服务器nginx转发到哪个地址我们是看不到的,这样就很难判断nginx代理是否生效。我们可以在nginx的配置文件上加上以下配置:

add_header backendIP $upstream_addr;

配置更新了之后,需要再重启一下Nginx服务。

nginx -s reload

如果不想加特殊前缀,也有其他的方式可以解决

3.1.history模式

history 模式会有一个问题,就是当页面刷新时,如果没有合适的配置,会出现页面 404 的错误,因此需要额外的配置。

try_files

try_files 解决的是:当 nginx 找不到客户端需要的资源时该怎么办的问题。对于找不到的 url,需要将首页 html 返回, nginx 配置如下:

location  / {
      try_files $uri $uri/ /index.html;
}

这样虽然解决了页面刷新404的问题,但是如果用post调用后端接口服务,会出现405 not allowed。这是因为 Nginx 会将匹配不上的url 匹配到首页html,但是html是静态资源,Nginx服务器默认post不能访问静态资源,所以会出现 405 not allowed。

error_page
error_page可以将所有POST 405错误发送到命名位置@405 , 配置如下:

location / {
    root   /usr/share/nginx/html;
    try_files $uri $uri/ /index.html;
    index  index.html index.htm;
    error_page 405 =200 @405;  #405页面处理
}

location @405 {         
     proxy_set_header Host $host; 
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_pass http://ip:端口$request_uri ;
}   

配置了之后接口访问正常

3.2 hash模式

hash不论页面的路由路径是什么,实际网络请求的都是主域名或IP:Port,所以并不会出现404问题。所以Nginx 配置并不需要加 try_files,但是路由找不到请求路径的文件,会出现404,所以需要配置 error_page。

location / {
    root   /usr/share/nginx/html;
    index  index.html index.htm;
    error_page 404 =200 @404;  #404页面处理
}

location @404 {         
     proxy_set_header Host $host; 
     proxy_set_header X-Real-IP $remote_addr;
     proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     proxy_pass http://ip:端口$request_uri ;
 }   

三、可能会出现的问题

1.Nginx报错405 Method Not Allowed

Request URL: http://localhost:8001/api/getinfo
Request Method: POST
Status Code: 405 Not Allowed
Remote Address: localhost:8001
Referrer Policy: strict-origin-when-cross-origin

前置情况:前端解决跨域问题、路由history模式

出现这个原因:正常情况下,接口地址可以直接设置后端接口地址,但是这样会引起浏览器跨域,如果后端没有设置接口允许跨域,那么就需要前端在nginx做一层转发。为了解决浏览器跨域问题,接口地址直接设置的业务系统访问地址,这接口就相当于去请求 /api/getinfo 这个路径下的文件,由于静态资源的,都不允许静态文件响应POST请求,只能通过get方法访问,所以这里就报错405。

解决方法:加前缀转发,或者配置配置405状态转发。

2. Nginx报错404 Not Found

前置情况:前端解决跨域问题、路由hash模式

出现这个原因:跟上面出现的情况一样,都是因为nginx配置问题,也是Nginx把接口请求当做访问静态资源,找不到文件就报错404。
解决方法:加前缀转发,或者配置配置404状态转发。

3. Nginx报错502 Bad Gateway

页面报错显示502 Bad Gateway,查看后端nginx发现并无前端的请求,并且后端服务没有问题。使用proxy_pass 中填写的地址用postman模拟是可以正常访问。

问题的原因是在于 nginx中传递了host,而后端也是nginx反向代理,而此nginx中并无原始请求的host,故报502错误。把Host的设置删掉即可。

proxy_set_header Host $host;

4. 接口返回HTML

这是因为nginx配置导致的

server {
     listen       80
     server_name  localhost;
     location / {
         root   html;
         index  index.html index.htm;
     }
     # To allow POST on static pages 允许静态页使用POST方法
     error_page  405     =200 $uri;
}

error_page 405 =200 $uri; 是将POST请求转换为GET。而使用此方法会出现返回不一致的问题,如这里应返回json文本,此处却是 html的文本,其原因就是因为请求的方式不一致,因返回格式不一致,导致前端报错。

在这里插入图片描述

在使用 `iframe` 加载资源时,浏览器出于安全策略的限制会阻止这种请求。如果目标是嵌入一个不同源的页面到当前页面中的 `iframe` 中,并且该页面是由自己控制的服务端(如后端 API 或前端静态服务),可以通过配置 Nginx 作为反向代理来解决问题。 ### 使用 Nginx 配置解决 iframe 问题 #### 1. 基本原理 通过 Nginx 将前后端服务统一映射到同一个名和端口下,使得前端页面与后端接口看似来自同一来源,从而绕过浏览器的同源策略限制。例如,前端服务部署在 `http://frontend:8081`,后端服务部署在 `http://backend:8080`,Nginx 可以将它们统一代理为 `http://proxy_name:8000/frontend` 和 `http://proxy_name:8000/backend`。 #### 2. Nginx 配置示例 以下是一个典型的 Nginx 配置片段,用于解决 `iframe` 问题: ```nginx http { upstream frontend { server frontend:8081; } upstream backend { server backend:8080; } server { listen 8000; server_name proxy_name; location /frontend { proxy_pass http://frontend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } location /backend { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } } ``` 通过上述配置前端页面可以访问 `http://proxy_name:8000/frontend`,而后端接口则通过 `http://proxy_name:8000/backend` 访问,两者共享相同的名和端口,避免了问题[^3]。 #### 3. 解决 iframe 的其他方法 除了使用 Nginx 代理外,还可以结合 `document.domain` 方法处理子之间的问题。假设前端应用部署在 `a.foo.com`,而后端服务部署在 `b.foo.com`,可以通过设置 `document.domain = 'foo.com'` 来实现两个页面之间的通信[^4]。 #### 4. CORS 的替代方案 如果不希望通过修改后端代码启用 CORS,Nginx 还可以通过添加响应头来模拟 CORS 行为。例如,在 `location` 块中添加以下内容: ```nginx add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range'; add_header 'Access-Control-Max-Age' 1728000; add_header 'Access-Control-Allow-Credentials' 'true'; ``` 这样即使后端未显式支持 CORS,也可以通过 Nginx 实现资源共享[^2]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值