V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
fstar
V2EX  ›  程序员

浏览器跨域请求,为什么简单请求直接就发送了,非简单请求还要先发一个 options 方法的预检请求?

  •  
  •   fstar · 2022-04-25 22:53:04 +08:00 · 3134 次点击
    这是一个创建于 970 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我觉得这是不是设计有问题。

    如果我来设计的话,不分什么简单不简单请求,全都先发一个 options 。或者全都直接直接发原请求。

    这样不上不下的设计真的很奇怪啊。

    23 条回复    2022-04-26 19:49:48 +08:00
    vance123
        1
    vance123  
       2022-04-25 22:59:20 +08:00
    为了前向兼容,前端里很多奇奇怪怪的地方都是有历史原因的
    sujin190
        2
    sujin190  
       2022-04-25 23:01:50 +08:00 via Android
    get 单独发浪费性能增加延迟吧,post 之类的直接发不泄露数据了吧,那你这跨域限制不废了么,这又不复杂的优化有啥难理解的
    lscho
        3
    lscho  
       2022-04-25 23:06:15 +08:00
    按你的理论,直接取消跨域就完事了。
    wwqgtxx
        4
    wwqgtxx  
       2022-04-25 23:07:49 +08:00
    总有人觉得自己能在十几年前预判现在的发展
    noe132
        5
    noe132  
       2022-04-25 23:09:23 +08:00
    简单来说因为历史原因。
    statumer
        6
    statumer  
       2022-04-25 23:09:56 +08:00 via iPhone
    照理说 jsonp 这个东西也是不应该存在的,都是历史包袱
    Chism
        7
    Chism  
       2022-04-25 23:17:59 +08:00 via Android
    @sujin190
    跨域请求 post 是先发个 get 试探,可以了再 post 吗?
    honkew
        8
    honkew  
       2022-04-25 23:21:59 +08:00
    需要拿到响应头,才能知道允不允许跨域啊
    yin1999
        9
    yin1999  
       2022-04-25 23:52:53 +08:00 via Android
    @Chism 用的是 option 请求,而非 get
    ch2
        10
    ch2  
       2022-04-26 00:04:40 +08:00   ❤️ 3
    因为浏览器加载 js 跟 html 、css 、jpg 这些静态文件默认都是 GET ,一个网站在打开的一瞬会大量加载这些文件。往往加载这些文件的时候不会携带 cookie 等机密数据,所以就不预先 option 了,完全没必要。但是 fetch 、xhr 、ajax 等发送请求往往是带 cookie 的,这时候又不好单独鉴别是不是 fetch 跟 xhr 、ajax 发的 GET 请求,所以就只给 POST 预检 option ,不管 GET 了
    ch2
        11
    ch2  
       2022-04-26 00:10:44 +08:00
    @ch2 #10 跨域主要是防止你的网站盗用别人网站的凭据刷 api ,这样至少可以保证别人盗用你网站 cookie 的 POST 发都发不出去
    Puteulanus
        12
    Puteulanus  
       2022-04-26 00:17:20 +08:00   ❤️ 1
    简单请求可以走其他方式发,比如 get 用图片的 src ,post 构造个表单直接 submit ,为了向上兼容不能拦这些,单独拦截异步请求发送的跨域请求就没有意义了
    复杂请求因为无法用这种手段构造,所以拦截跨域是有意义的,但是全拦了大家又不方便,所以改用 option 询问一下服务器该不该拦
    mxT52CRuqR6o5
        13
    mxT52CRuqR6o5  
       2022-04-26 00:50:14 +08:00 via Android
    因为有些接口有副作用,就比如转账接口,按照你的设计,虽然没有获取到转账结果,但转账请求发出去了
    tyx1703
        14
    tyx1703  
       2022-04-26 09:18:51 +08:00 via iPhone
    可能是因为简单请求的 http 报文小,发过去就算被拒绝了代价也比较小。非简单请求往往报文比较大,发过去再拒绝会造成资源浪费。而增加 options 预检,无论从时间还是空间维度,未增加过大负担,但带来的好处却显而易见。
    lisongeee
        15
    lisongeee  
       2022-04-26 09:24:31 +08:00
    @ch2

    “跨域主要是防止你的网站盗用别人网站的凭据刷 api ,这样至少可以保证别人盗用你网站 cookie 的 POST 发都发不出去”

    跨域中 简单请求 不需要预检,可以直接发出去,但是不一定收回来
    DOLLOR
        16
    DOLLOR  
       2022-04-26 09:25:05 +08:00
    所以,干脆所有接口都用 post+json ,不用纠结什么“简单请求”,就没那么多事了🐶
    weixiangzhe
        17
    weixiangzhe  
       2022-04-26 10:03:35 +08:00
    现在 chrome 是 有一次 option 成功,之后就没有 option 了吧
    lalalaqwer
        18
    lalalaqwer  
       2022-04-26 10:14:26 +08:00
    @weixiangzhe 服务端可以通过 http 头控制 option 的作用时间的
    fstar
        19
    fstar  
    OP
       2022-04-26 10:15:46 +08:00
    @weixiangzhe 哦,这个是缓存。`Access-Control-Max-Age: 86400` 可以设置缓存时间。
    bertonzh
        20
    bertonzh  
       2022-04-26 10:20:44 +08:00
    是有一些设计问题,比如 request 的 content-type 为 application/json 需要发预检,而 www-form-urlencoded 却不需要。明明这两种只是序列化的方式不同而已。
    另外如果自定义了 header ,也要发预检,这个也挺奇怪的。

    要我设计,就应该 GET 都不发,POST PUT 等都发。
    ssshooter
        21
    ssshooter  
       2022-04-26 12:35:31 +08:00
    get 是因为不改变服务器数据才让直接发的,post 发的有可能服务器已经处理完了(只是返回结果被浏览器拦截了),为了防止服务器被跨域修改数据才让 post 等方法先发 options 吧
    weixiangzhe
        22
    weixiangzhe  
       2022-04-26 13:33:46 +08:00
    @fstar 这样的吗,学习了
    lewinlan
        23
    lewinlan  
       2022-04-26 19:49:48 +08:00 via Android
    后端可以拦截 get
    前端只是尽力
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2721 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 35ms · UTC 12:50 · PVG 20:50 · LAX 04:50 · JFK 07:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.