RESTful API 实现中的跨域资源共享技巧

阅读时长 10 分钟读完

随着 web 应用的日益普及,前端开发中的 ajax 调用后端接口也越来越常见。在这个过程中,很容易遇到跨域问题,即 ajax 请求的目标服务端与当前页的域名不一致。本文将探讨 RESTful API 实现中的跨域资源共享技巧,介绍常见的跨域问题及解决方案。

什么是跨域请求

跨域请求,又称 CORS (Cross-Origin Resource Sharing),是指在浏览器之间进行 HTTP 请求时,由于当前页面的域名和请求的目标地址不同,导致浏览器在安全策略上做出的限制,请求被禁止。通俗地说,就是你用 ajax 请求一个不是你当前域名下的接口,请求会被禁止。

跨域资源共享的实现

CORS 是 W3C 标准,所有浏览器都支持。CORS 操作是浏览器自动完成的,不需要用户参与。相比 JSONP,CORS 的优势在于:

  • JSONP 只支持 GET 请求,而 CORS 支持所有类型的 HTTP 请求。
  • 使用 CORS,开发者可以使用普通的 XMLHttpRequest,将请求发送到任何想要使用的网站上。jsonp 的实现主要是在前端使用Script标签动态引入,不支持http header。
  • CORS 支持所有类型的 HTTP 认证,而 JSONP 只支持 GET 请求无法访问请求的响应头等其他信息。

大致原理:

  1. 客户端发起跨域请求。
  2. 服务端在响应头中添加 Access-Control-Allow-* 字段,表示允许客户端请求服务器。
  3. 客户端检查响应头中的 Access-Control-Allow-* 字段,确定是否可以继续执行请求。

前端实现

在 ajax 调用接口时,可以通过 XMLHttpRequest 对象的 setRequestHeader 方法设置请求头,包括 Origin、Credentials、Content-Type 等字段。服务器收到请求后,解析请求头,根据需要添加响应头。

-- -------------------- ---- -------
----- --- - --- -----------------
---------------- ----------------------------- ------
------------------------------------ --------------------
---------------------------------------- ------------------
------------------- - -----  -- -----------------------------

---------------------- - -------- -- -
  -- --------------- --- ------------------- -- ---------- --- ---- -
    --------------------------
  -
--

-------------------------
  ----- -----
  ---- --
----

后端实现

在服务端返回响应时,在响应头部分添加 Access-Control-Allow-* 字段。

-- -------------------- ---- -------
-- -- ---- --
----- --- - ---------------
----- --- - --- ------

------------- ----- ----- -- -
    ----------------------------------------------- ----- -- -----------
    ------------------------------------------------ -------------- --------------- -------------- ------- ------------------- -- -------------
    ------------------------------------------------ ----- ----- ---- ------- ---------- -- ------------

    -- ------------------- --- ---------- - -- ------
        ---------- - ----
        -------
    -

    ----- -------
---

------------- ----- ----- -- -
    -- --------- --- -------- -
        ----- -------
        -------
    -

    -- -------- ---- ---
    ----- ---- - ----- --- ----------------- ------- -- -
        ----- ------ - ---
        ------------------ ----- -- --------------------
        ----------------- -- -- -
            ----- ------ - ----------------------
            ----- ---- - ------------------
            --------------------------
        ---
    ---

    -- ------
    ----- - ----- --- - - -----
    ----- ------- - - --- -- ----- --- --
    -- ---------------
    -------- - --------
---

---------------- -- -- -
    ------------------- ------- -- ------------------------
---

常见问题及解决方案

1. 请求头携带Cookie无法发送

发送 ajax 请求时,浏览器默认不会携带 Cookie 信息,需要服务器设置响应头中的 Access-Control-Allow-Credentials 字段为 true。

前端代码:

后端代码:

2. 自定义请求头字段

默认情况下,浏览器只允许浏览器自定义请求头字段 X-Requested-With 和 Accept,则可以让服务端响应“Access-Control-Allow-Headers”头,该头部字段是对浏览器的指定。

前端代码:

后端代码:

3. 跨域请求的 PUT、DELETE 方法

浏览器默认不支持跨域请求的 PUT、DELETE 方法,需要服务器设置响应头中的 Access-Control-Allow-Methods 字段为 PUT、DELETE。

前端代码:

后端代码:

4. 预检请求 OPTIONS 的处理

对于跨域请求,浏览器在发送正式请求之前会先发送 OPTIONS 请求,用于获知服务端对于请求的支持情况、请求中是否合法以及是否有访问权限。常见返回码如下:

  • 200:表明该路由或方法在本次请求期间是合法的,浏览器可以继续发送真正的请求;
  • 403:表示该路由或方法在本次请求期间是非法的,浏览器不再继续发送真正的请求;
  • 404:表示该路由或资源不存在(但该方法依然合法),浏览器不再继续发送真正的请求;
  • 405:表示该路由虽然有效,但该方法是被禁止的,浏览器不应再次发送带有相同路径和方法的请求。
  • 206:表示请求内容范围未得到满足,请求头 Range 指定的范围超出实际范围。将Range Range: bytes=0-5

前端代码:

-- -------------------- ---- -------
---------------- ----------------------------- ------
------------------------------------ --------------------
---------------------------------------- ------------------
------------------- - -----

-- --------------- --- ------------------- -- ---------- --- ---- -
  --------------------------
- ---- -- --------------- --- ------------------- -- ---------- --- -- -
  ------------------ -------
  -------------------------
    ----- -----
    ---- --
  ----
- ---- -- --------------- --- ------------------- -- ---------- --- ---- -
  ------------------------
- ---- -
  ------------------------
-

后端代码:

-- -------------------- ---- -------
------------- ----- ----- -- -
  -- ------------------- --- ---------- - -- ------
    -------- - ---
    ----------------------------------------------- -----
    ------------------------------------------------ -------------- --------------- -------------- ------- -------------------
    ------------------------------------------------ ----- ----- ---- ------- ----------
    ------------------------------------------ --------- -- ------ -- -
    ------------------- - ----
    -------
  -

  ----- -------
---

总结

总的来说,CORS 协议是一种用来解决跨域问题的标准,它通过在服务端添加一些响应头,来告知浏览器跨域请求是否允许。IE 10 以下比较麻烦,不过通常前后端工程师会考虑到这点,解决方法大致分以下几点:

  • 需要客户端发送请求时,设置 withCredentials 字段;
  • 设置响应头 Access-Control-Allow-Origin 为 *,或是请求来自的地址;
  • 如果用户自定义 header ,需要服务端请求头部中添加相应的响应头 Access-Control-Allow-Headers;
  • 如果服务端允许跨域请求的 PUT、DELETE 方法,需要添加 Access-Control-Allow-Methods 响应头;
  • 添加 OPTIONS 预检请求,对后端响应头进行增加,保证与真实请求相同条件。
  • 处理 OPTIONS 预检请求,推荐使用 nookies 这个轮子。

来源:JavaScript中文网 ,转载请注明来源 https://www.javascriptcn.com/post/647d5340968c7c53b0823e4e

纠错
反馈