说一说跨域

340 阅读2分钟

啥是跨域?

来自于浏览器的同源策略,当协议,域名,端口号任何一个不同时,都算作不同域,不同域之间相互请求资源,就叫作“跨域”

怎么解决跨域?

前端解决跨域 proxy

我们以vue为例,解决跨域问题。 在vue.config.js中用webpack devServer的proxy设置代理避免跨域

devServer:{
    port:port,
    proxy:{
        //代理 /api/user/login  到  http://127.0.0.1:3000/user/login
        '/api/': {
        target: `http://127.0.0.1:3000/`,
        changeOrigin: true
      }
    }
}

前端+后端 绕过跨域 jsonp

前端构造<script>标签,请求指定url(由script发出的get请求不受同源策略限制),服务器返回一个函数执行语句,该函数名称通常由查询参callback的值决定,函数的参数为服务器返回的json数据。该函数在前端执行后即可获取数据

后端解决跨域

以node为例使用http-proxy-middleware 中间件

const {createProxyMiddleware} = require('http-proxy-middleware')
//代理到http://localhost:4000 真实服务器
app.use('/api', createProxyMiddleware({ target: 'http://localhost:4000', changeOrigin: true }));

CORS跨域资源共享

原理:cors是w3c规范,真正意义上解决跨域问题。它需要服务器对请求进⾏检查并对响应头做相应处理,从⽽允许跨域请求。

具体实现

  • 响应简单请求:动词为get/post/head,没有自定义请求头,Content-Type是application/x-wwwform-urlencoded,multipart/form-data或text/plain之⼀,通过添加以下响应头解决:
//设置响应头:允许http://localhost:3000访问
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000')
  • 假设我们添加自定义请求头x-token,使请求变为预检查请求

响应preflight请求,需要响应浏览器发出的options请求(预检请求),并根据情况设置响应头

if (method == "OPTIONS" && url == "/api/users") {
  res.writeHead(200, {
   //表明服务器允许 http://localhost:3000 访问api
  "Access-Control-Allow-Origin": "http://localhost:3000",
   //表明服务器允许请求中携带字段X-TOKEN 与Content-Type
  "Access-Control-Allow-Headers": "X-Token,Content-Type",
   //表明服务器允许客户端使用 POST,GET 和 OPTIONS 方法发起请求。
  "Access-Control-Allow-Methods": "GET,POST,OPTION"
   });
  res.end();
}else if (method == "GET" && url == "/api/users") {
    res.setHeader("Content-Type", "application/json");
    res.setHeader("Access-Control-Allow-Origin", "http://localhost:3000",)
    res.end(JSON.stringify([{ name: "tom", age: 20 }]));

如图,发起了两次请求,第一次是OPTIONS预检请求

nginx反向代理

我们可以在发布阶段配置nginx,我们看一下反向代理的工作原理:**客户端向反向代理发送请求,接着反向代理转发请求至目标服务器,并把获得的内容返回给客户端 **

配置如下:

server {
        listen       80;   #监听80端口
        server_name  localhost;    #访问该域名进到nginx配置中来
        location / {    #访问根目录,前端页面
            root   html/dist;    #存放页面根目录
            index  index.html index.htm;
            try_files $uri $uri/ /index.html;    #配合vue  router history模式
        }
        location /api {    #访问 /api
            
            proxy_pass  http://127.0.0.1:8081;    #代理到后端接口
            proxy_redirect  off;
            proxy_set_header    Host                $host;
            proxy_set_header    X-Real-IP           $remote_addr;
            proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
        }
}