在前端本地环境在调用第三方接口,常会遇到No 'Access-Control-Allow-Origin' header is present on the requested resource
错误,这是因为浏览器的同源策略拒绝了我们的请求。
什么是同源?
如果两个url的协议、域名、端口相同,就称这两个url是同源比如
http://xxx.com:80/index.html
和http://xxx.com:80/dir/index.html
是同源,而https://xxx:80/index.html
和http://xxx:80/index.html
不同源,因为协议不同。
同源策略主要表现在DOM、Web数据和Web网络三个层面:
同源策略的出发点是好的,保护数据的安全性,但也影响着开发的便利性,给开发者造成困难,比如不能正常访问非同源的第三方网络接口。
对于网络请求,我们可以用nginx来代理转发接口,避开浏览器同源策略的限制。
nginx安装配置还是比较简单的,下载解压后就可以正常启动
nginx下载: http://nginx.org/en/download.html
下载后解压存放你想放的目录下,比如我的:
启动nginx有两种方式:
建议使用cmd命令启动,以管理员身份启动cmd,进入安装目录,执行启动命令start nginx.exe
H:\Program Files (x86)\nginx-1.22.1>start nginx.exe
命令执行后会有黑色窗口一闪而过,是正常现象。
验证是否启动成功,可以通过nginx -v
命令查看版本号,或者预览http://localhost
是否正常打开:
关于电脑开机自动启动nginx,可以参考这篇,如果只是临时调试用,上面足够用了。
https://blog.csdn.net/xiaojin21cen/article/details/84622517
start nginx.exe ## 启动服务
nginx.exe -s stop ## 快速停止服务
nginx.exe -s quit ## 优雅的 停止服务
nginx.exe -s reload ## 重新加载 配置文件,这命令可以不用停止nginx
nginx.exe -s reopen ## 重新打开日志文件
由于浏览器的同源策略,在本地调试接口时出现无法访问问题,通过nginx反向代理转发接口就可以正常访问。
nginx反向代理原理:
客户端本来可以直接通过HTTP协议访问某网站应用服务器,如果网站管理员在中间加上一个nginx,客户端请求nginx,nginx请求应用服务器,然后将结果返回给客户端,此时nginx就是反向代理服务器。
比如我现在通过XMLHttpRequest请求https://www.wanandroid.com/project/list/1/json
首先在打开nginx.conf
文件,在http{...}
作用域中配置代理信息。
H:\Program Files (x86)\nginx-1.22.1\conf\nginx.conf
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
# 连接超时时间,服务器会在这个时间过后关闭连接
keepalive_timeout 65;
# 直接请求nginx也是会报跨域错误的这里设置允许跨域
# 如果代理地址已经允许跨域则不需要这些, 否则报错(虽然这样nginx跨域就没意义了)
# 如果客户端设置了withCredentials,Access-Control-Allow-Origin就是设置全通配*,应该设置指定的应用服务名,比如http://localhost:8080
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Headers X-Requested-With;
add_header Access-Control-Allow-Methods GET,POST,OPTIONS;
# srever模块配置是http模块中的一个子模块,用来定义一个虚拟访问主机
# 可以配置多个srever模块
server {
# 监听80端口,可以随意改
listen 80;
# 应用服务器的IP或者host
# 如果是本地服务:localhost或者本机ip
server_name localhost;
# 根路径指到index.html
location / {
root html;
index index.html index.htm;
}
# localhost/project 的前缀请求会转发到https://www.wanandroid.com
location /project {
# 转发地址
proxy_pass https://www.wanandroid.com;
}
# 重定向错误页面到/50x.html
location = /50x.html {
root html;
}
}
}
关于listen
端口号的设置,可以随意改,只要不和其他端口号冲突就可以,比如端口号改成1688,那么url请求建议使用本机ip,通过ipconfig
命令查看ip,比如是192.168.0.11。配置如下:
server {
listen 1688;
# 使用localhost或192.168.0.11
server_name 192.168.0.11;
}
# 网络请求url改成 http://192.168.0.11:1688/xxxx/yyyy
# 如果不改listen的情况,默认就是 http://localhost/xxxx/yyyy
关于本机ip和localhost、127.0.0.1的区别,可以参考这篇 https://www.jianshu.com/p/ad7cd1d5be45
每次修改nginx配置后,记得保存然后执行重载命令nginx -v reload
才会生效。
前端代码:
// 原本URL: https://www.wanandroid.com/project/list/1/json
// 改成代理服务server_name来请求
let url = "http://localhost/project/list/1/json"
let params = new URLSearchParams()
params.append("cid","294")
let xhr = new XMLHttpRequest()
// xhr.withCredentials = false
xhr.open("GET",url)
xhr.send(params)
xhr.onload = () =>{
if (xhr.status === 200){
console.log("resp: "+xhr.response)
}
}
最后可以正常看到response日志的输出。
注意:在nginx的每一条配置末尾必须加上
;
,不然会报错nginx: [emerg] unexpected "}"
nginx代理配置重点在location
上,一些常用的配置需求:
localtion / {
# 所有请求都匹配以下规则
# 因为所有的地址都以 / 开头,所以这条规则将匹配到所有请求
# pass_proxy 等其他配置写在这里
}
location = / {
# 精确匹配 / ,后面带任何字符串的地址都不符合
}
localtion /api {
# 匹配任何 /api 开头的URL,包括 /api 后面任意的, 比如 /api/getList
# 匹配符合以后,还要继续往下搜索
# 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
}
localtion ~ /api/abc {
# 匹配任何 /api/abc 开头的URL,包括 /api/abc 后面任意的, 比如 /api/abc/getList
# 匹配符合以后,还要继续往下搜索
# 只有后面的正则表达式没有匹配到时,这一条才会采用这一条
}
更详细的配置可以参考:https://segmentfault.com/a/1190000002797606