跨域系列

269 阅读2分钟
  • 对于此地址 https://juejin.cn/editor/drafts/7073721444034674719
  1. 协议 -> https
  2. host -> juejin.cn
  3. port -> 默认80
  • 同源策略 [协议hostport完全一样属于同源]

  • 跨域出错标志:CORS error -> Cross-Origin Resource Sharing error. MissingAllowOriginHeader.

  • 预检请求 Option

    • 非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUTDELETE,或者Content-Type字段的类型是application/json
    • 非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。
    • 浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。
  • 浏览器访问b.html下的服务器,跨域的几种解决方案

image.png

  1. 在后端接口添加响应头 "Access-Control-xxxx-xxxx" 或者使用 @CrossOrigin

  2. 手写java反向代理解决跨域

    • 劫持前端的请求,后端通过RestTemplate修改url重新发送请求
  # application-dev.properties
    server.port=8081
    proxy.address=http://127.0.0.1:8082

  @RestController
  public class ProxyController {
  
    @Resource
    private RestTemplate restTemplate;
    
    @Value("${proxy.address}")
    private String proxyAddress;
    
    @RequestMapping("/api/**")
    public Object proxy(HttpServletRequest request) {
      return restTemplate.getForObject(proxyAddress + request.getRequestURI().replace("/api", ""), Object.class);
    }    
  }
 
  1. nginx反向代理解决跨域
  • 关于正向/反向代理,假设有客户代理服务器目标服务器
    • 正向代理指客户不清楚代理服务器的情况下,直接访问目标服务器
    • 反向代理指客户明确访问代理服务器,然后代理服务器访问目标服务器把资源返回给客户,但此过程客户不清楚
    • 正向代理表示为输入真实的目标服务器地址,反向代理表示输入代理服务器地址
    • nginx
      1. nginx是一个静态服务器

      2. 启动nginx.exe,默认启动在127.0.0.1:80,注意port是80

      3. 找到文件nginx.conf,vim 配置该文件

      4. 不同@RequestMapping的配置方式

        • 访问地址http://127.0.0.1:80/api/user后端@RequestMapping("/api/user")
        server {
           listen                80;                // 监听80端口
           server_name    localhost;                // 服务地址
        
           location /api {                          // 只要匹配到以`/api`开头的就拦截
              proxy_pass http://127.0.0.1:8082;     // 然后跳转至http://127.0.0.1:8082
           }
        }
        
        • 访问地址http://127.0.0.1:80/api/user后端@RequestMapping("/user")
        server {
           listen                80;                // 监听80端口
           server_name    localhost;                // 服务地址
        
           location /api {                          // 只要匹配到以`/api`开头的就拦截
              rewrite ^/api/(.*)$ /$1 break;        // ^/api代表以api开头的,(.*)代表任意字符,/$1表示取出第一个$内的任意字符,然后rewrite重写,详情了解正则表达式 
              proxy_pass http://127.0.0.1:8082;     // 然后跳转至http://127.0.0.1:8082
           }
        }
        
      5. 配置完成执行命令nginx -t检查配置是否正确,再执行命令nginx -s reload重新加载nginx

  1. 前后分离项目之Vue解决跨域
    • 访问地址http://127.0.0.1:80/api/user

    • vue.config.js文件下,写入如下代码

      # process.env.VUE_APP_BASE_API=/api
      
      proxy: {
          [process.env.VUE_APP_BASE_API]: {
              target: `http://127.0.0.1:8082`,
              changeOrigin: true,
              pathRewrite: {
                ['^' + process.env.VUE_APP_BASE_API]: '/test'
              }
          }
      }
      

      经过改写后生成http://127.0.0.1:8082/test/user

    • vue打包之后实际上是html+js文件,是没有反向代理的能力的,最终还是需要放到nginx上解决跨域,此处可以通过改写生成nginx所需的地址,与nginx集成

  2. JSONP解决跨域
    • <script>天然支持跨域
    • 前后端配合
      • 前端
        <script>
           function cross(data) {
              console.log(data);
           }
        </script>
        
        <script src="http://127.0.0.1:8082/cross"></script>
        
      • 后端
        @RequestMapping("/cross")
        public String cross() {
           return "cross("Hello world!")";
        }
        
    • 优点 支持IE
    • 缺点
      • 由于是 <script> 标签,所以读不到 ajax 那么精确的状态,不知道状态码是什么,也不知道响应头是什么,它只知道成功和失败。
      • <script> 标签只支持 get 请求,不支持post请求