- A+
首先,最简单的一版。对于/api开头的接口,转发到后端地址http://localhost:20009。然后设置Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers来解决跨域。
server { listen 80; server_name localhost; location /api { add_header Cache-Control 'private, no-store, max-age=0'; proxy_pass http://localhost:20009 ; add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'ft-token,Set-Cookie,Security-Token,Request-Id,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; } }
这样配置,不出意外的报错了,前端浏览器控制台报错如下:
institution:1 Access to XMLHttpRequest at 'http://localhost/api//base/page' from origin 'http://localhost:8081' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
因为前端需要发送OPTIONS预请求,但nginx配置中没有处理OPTIONS请求,在OPTIONS请求时也要加上headers返回。所以修改后的第二版如下:
server { listen 80; server_name localhost; location /api { add_header Cache-Control 'private, no-store, max-age=0'; if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'ft-token,Set-Cookie,Security-Token,Request-Id,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; return 200; } proxy_pass http://localhost:20009 ; add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'ft-token,Set-Cookie,Security-Token,Request-Id,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; } }
然后,又一个坑来了。前端控制台报错:
institution:1 Access to XMLHttpRequest at 'http://localhost/api/base/page' from origin 'http://localhost:8081' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
这个报错说的是,如果前端请求带了credentials,那么返回的请求头Access-Control-Allow-Origin就不能是*。好吧,将Access-Control-Allow-Origin改成具体的地址,第三版:
server { listen 80; server_name localhost; location /api { add_header Cache-Control 'private, no-store, max-age=0'; if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' 'http://localhost:8081'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'ft-token,Set-Cookie,Security-Token,Request-Id,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; return 200; } proxy_pass http://localhost:20009 ; add_header 'Access-Control-Allow-Origin' 'http://localhost:8081'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'ft-token,Set-Cookie,Security-Token,Request-Id,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; } }
第三版继续报错:
Access to XMLHttpRequest at 'http://localhost/api/base/page' from origin 'http://localhost:8081' has been blocked by CORS policy: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
意思是说如果前端请求带了credentials,那么返回的请求头里Access-Control-Allow-Credentials必须设为'true'。第四版:
server { listen 80; server_name localhost; location /api { add_header Cache-Control 'private, no-store, max-age=0'; if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' 'http://localhost:8081'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'ft-token,Set-Cookie,Security-Token,Request-Id,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; add_header 'Access-Control-Allow-Credentials' 'true'; return 200; } proxy_pass http://localhost:20009 ; add_header 'Access-Control-Allow-Origin' 'http://localhost:8081'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'ft-token,Set-Cookie,Security-Token,Request-Id,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; add_header 'Access-Control-Allow-Credentials' 'true'; } }
好了,第四版请求一般的接口已经OK了,但需要注意一点的是,我们使用nginx来解决跨域问题,那么后端那边就不要处理跨域了,如果后端也处理了跨域,那么可能就会出问题。比如后端返回了Access-Control-Allow-Origin为*,那么就会报错如下:
Access to XMLHttpRequest at 'http://localhost/api//role_permissions?t=1718851982740' from origin 'http://localhost:8081' has been blocked by CORS policy: The 'Access-Control-Allow-Origin' header contains multiple values '*, http://localhost:8081', but only one is allowed.
意思是Access-Control-Allow-Origin返回了两个值,*和http://localhost:8081,但只能返回一个,不然还是会跨域,原因是nginx设置了一个,后端也设置了一个,所以要么是后端的处理去掉,如果不能动后端代码的话,我们可以想办法在nginx层解决,即nginx强制把后端返回的Access-Control-Allow-Origin头覆盖掉。
于是。第五版来了,加上proxy_hide_header 'Access-Control-Allow-Origin';就可以在nginx里把后端返回的Access-Control-Allow-Origin头无效掉
server { listen 80; server_name localhost; location /api { add_header Cache-Control 'private, no-store, max-age=0'; if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' 'http://localhost:8081'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'ft-token,Set-Cookie,Security-Token,Request-Id,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; add_header 'Access-Control-Allow-Credentials' 'true'; return 200; } proxy_pass http://localhost:20009 ; proxy_hide_header 'Access-Control-Allow-Origin'; add_header 'Access-Control-Allow-Origin' 'http://localhost:8081'; add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, OPTIONS'; add_header 'Access-Control-Allow-Headers' 'ft-token,Set-Cookie,Security-Token,Request-Id,DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization'; add_header 'Access-Control-Allow-Credentials' 'true'; } }
好了,至此,就OK了。这块还是踩了不少坑的。