zoukankan      html  css  js  c++  java
  • Laravel解决预请求和跨域的问题

    场景描述

      最近在做公司的一个项目,我们在做这个小项目的时候,决定采用三端分离,数据库、服务器端、前端都分离。这样的分离是好的,但是我们遇到了一个问题,这个问题就是跨域问题和预请求问题。跨域的问题是因为我们将前端和后端放在两台服务器,数据之间的访问是通过RestApi进行的,这个时候的访问就涉及跨域的问题。还有一个问题就是预请求的问题,这个问题的引发就是在访问Api的时候要携带令牌,没有令牌是不能访问的。前端每次在访问接口的时候都要在请求头加上Token,加上token之后就出现了预请求的问题。为了解决预请求太搞脑子。下面我们就来说说预请求的问题。

    CORS描述

    一、CORS定义

      跨来源资源共享(CORS)是一份浏览器技术的规范,提供了 Web 服务从不同网域传来沙盒脚本的方法,以避开浏览器的同源策略,是 JSONP 模式的现代版。与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 要求。用 CORS 可以让网页设计师用一般的 XMLHttpRequest,这种方式的错误处理比JSONP要来的好,JSONP对于 RESTful 的 API 来说,发送 POST/PUT/DELET 请求将成为问题,不利于接口的统一。但另一方面,JSONP 可以在不支持 CORS 的老旧浏览器上运作。不过现代的浏览器(IE10以上)基本都支持 CORS。

    二、简单请求和非简单请求

      只要同时满足以下两大条件,就属于简单请求。否侧就是非简单请求。

    (1) 请求方法是以下三种方法之一:
    
           HEAD
           GET
           POST
    (2)HTTP的头信息不超出以下几种字段:
    
          Accept
          Accept-Language
          Content-Language
          Last-Event-ID
          Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

    对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。

    GET /cors HTTP/1.1
    Origin: http://api.bob.com
    Host: api.alice.com
    Accept-Language: en-US
    Connection: keep-alive
    User-Agent: Mozilla/5.0...

    非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUTDELETE,或者Content-Type字段的类型是application/json或者自定义请求头信息

    非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

    非简单请求两个重要的参数:

      1、Access-Control-Request-Method:该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法。

      2、Access-Control-Request-Headers:该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段。

    三、预检请求定义

      在 CORS 中,可以使用 OPTIONS 方法发起一个预检请求(一般都是浏览检测到请求跨域时,会自动发起),以检测实际请求是否可以被服务器所接受。预检请求报文中的 Access-Control-Request-Method 首部字段告知服务器实际请求所使用的 HTTP 方法;Access-Control-Request-Headers 首部字段告知服务器实际请求所携带的自定义首部字段。服务器基于从预检请求获得的信息来判断,是否接受接下来的实际请求。

    预检请求的过程 

      

    由上面图可以看出,解决预请求是靠服务器来解决。

    请求失败的结果:如果失败请求头的Token就不能加上去

    请求成功的结果

    laravel怎么实现OPTIONS请求

      我在网上找了好多资料,看了之后都不能解决预检测的问题,因为项目的需要,需要在所有的Api接口的访问携带Token,这个时候我们注册中间件就要注册全局的,而不是路由的。

    注意:我第一次在路由里面直接注册中间件,还是不能成功响应。通过调试发现Laravel预检测不能放在路由的中间件里面,如果放在哪就不生效。我们要放在全局中间件里面或者直接放在路由里面。

    见代码

    public function handle($request, Closure $next)
        {
            $response = $next($request);
            $response->header('Access-Control-Allow-Origin', '*');
            $response->header('Access-Control-Allow-Headers', 'Origin,No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With, token');
            $response->header('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, OPTIONS');
            $response->header('Access-Control-Allow-Credentials', 'true');
            //验证token是否
            $token = $request->header('token');
            if(!$token){
                return Base::response('授权失败,请检查token',0);
            }else{
                $res = (new Token())->verifyToken($token);
                if(!$res){
                    return Base::response('token失效,请重新获取',0);
                }
            }
            return $response;
        }
    

    注册中间件

      protected $middleware = [
            IlluminateFoundationHttpMiddlewareCheckForMaintenanceMode::class,
            IlluminateFoundationHttpMiddlewareValidatePostSize::class,
            AppHttpMiddlewareTrimStrings::class,
            IlluminateFoundationHttpMiddlewareConvertEmptyStringsToNull::class,
            AppHttpMiddlewareCorsHttp::class,
        ];
    

    最后大功告成,希望可以帮助到大家。

      

  • 相关阅读:
    QT5控件-QDateTimeEdit和类QDateTime
    QT5-控件-QTimeEdit和QTime
    QT5-控件-QDateEdit 和 日期类QDate
    QT5-控件-QComboBox
    错误记录 "MongoClient opened before fork. Create MongoClient "
    GitHub 常用命令
    Linux学习记录-----《快乐的Linux命令行》.
    最全的HTTP1.1状态码
    恢复旋转排序数组
    C语言I博客作业09
  • 原文地址:https://www.cnblogs.com/meichao/p/9288729.html
Copyright © 2011-2022 走看看