<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          next.js 如何正確處理跨域問(wèn)題?

          共 5635字,需瀏覽 12分鐘

           ·

          2024-03-29 01:30

          這是「進(jìn)擊的Coder」的第 911  篇技術(shù)分享 作者:kingname 來(lái)源:未聞 Code

          閱讀本文大概需要 6 分鐘。



          我以前一直使用 Vue 來(lái)寫前端。去年下半年接手了一個(gè)基于 React + Next.js 的項(xiàng)目,于是順帶學(xué)習(xí)了一下 Next.js。由于 Next.js 的特點(diǎn),這個(gè)項(xiàng)目的前后端是放在一起的。一開始沒(méi)什么問(wèn)題,看了半天文檔就上手了。

          上周我們需要在另一個(gè)網(wǎng)頁(yè)項(xiàng)目中,調(diào)用這個(gè)項(xiàng)目的后端接口,于是就需要處理跨域請(qǐng)求的問(wèn)題。但我發(fā)現(xiàn)按照網(wǎng)上的方法,跨域問(wèn)題依然存在。這個(gè)問(wèn)題浪費(fèi)了我不少時(shí)間,好在最后終于找到了原因。記錄在這里,免得大家跟我一樣踩坑。

          為了復(fù)現(xiàn)這個(gè)問(wèn)題,我們先來(lái)創(chuàng)建一個(gè) Next.js 項(xiàng)目。執(zhí)行代碼創(chuàng)建代碼腳手架:

                npx create-next-app test_cors

          使用 TypeScript,其他選項(xiàng)選擇默認(rèn),如下圖所示:

          71ea82ded45e6e6da11066c3c0b19013.webp

          命令執(zhí)行完成以后,會(huì)生成一個(gè)test_cors文件夾,在文件夾中創(chuàng)建文件pages/api/test.ts。內(nèi)容如下:

                import { NextResponse } from 'next/server'


          export const config = {
              runtime: "edge"
          }

          export interface UserInfo {
              name: string
              age: number
              address: string
          }


          const handler = async (req: Request): Promise<Response> => {
              
              const user = (await req.json()) as UserInfo
              return NextResponse.json({success: true,
                                        msg: `你的名字是${user.name}, 今年${user.age}歲`})
          }

          export default handler;

          如下圖所示:

          dd051a44f307bc88565ffff421f34abf.webp

          然后運(yùn)行命令npm run dev。這個(gè)后端接口就啟動(dòng)起來(lái)了。我們可以使用 Postman 來(lái)進(jìn)行測(cè)試:

          3806175fa43ac62b1b0b69219bc28c37.webp

          接下來(lái),我們來(lái)寫一段 HTML 代碼,觸發(fā)跨域問(wèn)題:

                <!DOCTYPE html>
          <html lang="zh-CN">
          <head>
              <meta charset="UTF-8">
              <title>API 請(qǐng)求示例</title>
              <script>
                  // 當(dāng)按鈕被點(diǎn)擊時(shí)執(zhí)行此函數(shù)
                  function sendRequest() {
                      // 創(chuàng)建一個(gè)新的 XMLHttpRequest 對(duì)象
                      var xhr = new XMLHttpRequest();

                      // 配置請(qǐng)求類型、URL 以及異步處理
                      xhr.open('POST''http://127.0.0.1:3000/api/test'true);

                      // 設(shè)置請(qǐng)求頭
                      xhr.setRequestHeader('Content-Type''application/json');
                      // ... 其他請(qǐng)求頭設(shè)置

                      // 設(shè)置響應(yīng)類型
                      xhr.responseType = 'json';

                      // 定義請(qǐng)求完成的回調(diào)函數(shù)
                      xhr.onload = function () {
                          if (xhr.status === 200) {
                              // 請(qǐng)求成功,處理響應(yīng)數(shù)據(jù)
                              document.getElementById('response').innerText = JSON.stringify(xhr.response);
                          } else {
                              // 請(qǐng)求失敗,處理錯(cuò)誤
                              document.getElementById('response').innerText = '請(qǐng)求失敗: ' + xhr.status;
                          }
                      };

                      // 發(fā)送請(qǐng)求
                      xhr.send(JSON.stringify({name"青南"age20"address""上海"}));
                  }
              </script>

          </head>
          <body>
              <button onclick="sendRequest()">發(fā)送請(qǐng)求</button>
              <div id="response"></div>
          </body>
          </html>

          直接雙擊打開這個(gè) html 文件,點(diǎn)擊頁(yè)面上的按扭,就會(huì)觸發(fā)跨域報(bào)錯(cuò),如下圖所示:

          e676248df3e0816927dec93edb7f2e18.webp

          然后,你在網(wǎng)上用關(guān)鍵詞搜索next.js 跨域或者next.js cors,一般看到的文章都會(huì)讓你直接在next.config.js文件中添加響應(yīng)頭,如下圖所示:

          07b6cf511b73f7e57ce830d29b081124.webp

          你按照這些文章中寫到方法加了配置,重啟服務(wù),然后用 Postman 來(lái)測(cè)試,你會(huì)發(fā)現(xiàn)返回的響應(yīng)頭里面確實(shí)已經(jīng)有這幾項(xiàng)了,如下圖所示:

          6667626bc532702b1095409851d5e7d6.webp

          但當(dāng)你使用 HTML 頁(yè)面來(lái)測(cè)試時(shí),跨域的報(bào)錯(cuò)還在。

          你連續(xù)打開 Google 上面 10 篇講 Next.js 跨域的文章,無(wú)論是中文博客還是英文博客,甚至你直接使用 ChatGPT 來(lái)問(wèn),他們給你的回復(fù)肯定都是上面的這個(gè)方法。但是無(wú)論你怎么測(cè)試,跨域問(wèn)題還在。

          實(shí)際上,跨域就是這樣配置的。你的配置沒(méi)有任何問(wèn)題。問(wèn)題出現(xiàn)在你的后端代碼上,如下圖所示:

          9df65e986301b4267217864793b20a0e.webp

          首先你需要是一個(gè)POST請(qǐng)求,你才能執(zhí)行await req.json()。而瀏覽器在判斷能不能跨域時(shí),會(huì)首先發(fā)送一個(gè)OPTIONS請(qǐng)求,如下圖所示:

          3c4655d799eab92500a5edf016fff6ba.webp

          這個(gè)請(qǐng)求也會(huì)走到你的這段后端代碼里面。但由于 OPTIONS 請(qǐng)求沒(méi)有 Body,于是代碼運(yùn)行到await req.json()時(shí),就會(huì)報(bào)錯(cuò)。于是瀏覽器認(rèn)為OPTIONS請(qǐng)求沒(méi)有返回 status 200,因此強(qiáng)行認(rèn)為你的接口不支持跨域。

          那么解決方法也非常簡(jiǎn)單,提前判斷一下請(qǐng)求方法是不是 OPTIONS 就可以了:

                if(req.method === 'OPTIONS') {
              return NextResponse.next()
          }

          如下圖所示:

          d0bb2f1bd3fd02dba4f227bc4609a7e5.webp

          運(yùn)行效果如下圖所示,跨域成功:

          84a7f2bd42fde90a7efa0b6b86b1ad33.webp

          這個(gè)問(wèn)題對(duì)于資深前端來(lái)說(shuō),可能不值一提。但對(duì)于后端兼職前端的人,或者第一次接觸 Next.js 的人來(lái)說(shuō),可能是一個(gè)深坑,會(huì)浪費(fèi)很多的時(shí)間。


          好文和朋友一起看~


          瀏覽 148
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  永久免费 看片直接看 | av777777 | 色色色色色色色色色五月婷婷 | 激情无码嗯啊一区 | 欧美精品成人在线 |