Berbagi teknologi

Pahami secara menyeluruh lintas-domain front-end

2024-07-12

한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina

 

Daftar isi

1Kebijakan asal yang sama dari browser

1.1 Ikhtisar Kebijakan Asal yang Sama

1.2 Apa yang dimaksud dengan asal usul?

2. Apa saja batasan transaksi lintas domain?

2.1 Batasi akses DOM

2.2 Membatasi Akses Cookie

2.3 Batasi Ajax untuk memperoleh data

3 poin yang perlu diperhatikan

4CORS memecahkan masalah lintas domain Ajax

4.1 Ikhtisar CORS

4.2CORS menyelesaikan permintaan lintas domain sederhana

4.3 Permintaan sederhana dan permintaan kompleks

4.4CORS menyelesaikan permintaan lintas domain yang kompleks

4.5 Gunakan perpustakaan cors untuk menyelesaikan konfigurasi dengan cepat

5JSONP memecahkan masalah lintas domain

6Konfigurasi proksi untuk menyelesaikan masalah lintas domain

6.1 Konfigurasikan sendiri server proxy

6.2 Gunakan Nginx untuk membangun server proxy

6.3 Membangun server dengan bantuan scaffolding


Alamat kode git clone https://gitee.com/childe-jia/cross-domain-test.git

1Kebijakan asal yang sama dari browser

1.1 Ikhtisar Kebijakan Asal yang Sama


Kebijakan asal yang sama adalah kebijakan yang diikuti browser untuk memastikan keamanan sumber daya. Kebijakan ini menerapkan beberapa pembatasan pada akses ke sumber daya.
Deskripsi kebijakan asal yang sama dari W3C:Kebijakan asal yang sama

1.2 Apa yang dimaksud dengan asal usul?


1 komponen sumber

gambar.png


2Pada tabel di bawah, hanya dua sumber pada baris terakhir yang mempunyai asal yang sama.

Sumber 1

Sumber 2

Apakah itu homolog?

http://www.xyz.com/rumah

https://www.xyz.com/rumah

⛔Tidak homogen️

http://www.xyz.com/rumah

http://mail.xyz.com/beranda

⛔Tidak homogen

http://www.xyz.com:8080/rumah

http://www.xyz.com:8090/rumah

⛔Tidak homogen

http://www.xyz.com:8080/rumah

http://www.xyz.com:8080/pencarian

✅Asal yang sama︎

 

3 permintaan asal

gambar.png


4 Permintaan tidak asli

gambar.png


5 Ringkasan: Jika "sumber" tidak sesuai dengan "sumber target", itu berarti "non-sumber", juga dikenal sebagai "heterosource" atau "lintas-domain"

2. Apa saja batasan transaksi lintas domain?


Misalnya, jika ada dua sumber: "Sumber A" dan "Sumber B", yang "asalnya tidak sama", maka browser akan memiliki batasan berikut:

2.1 Batasi akses DOM

Skrip "Sumber A" tidak dapat mengakses DOM "Sumber B".

  1. <!-- <iframe id="framePage" src="./demo.html"></iframe> -->
  2. <iframe id="framePage" src="https://www.baidu.com"></iframe>
  3. <script type="text/javascript" >
  4. function showDOM(){
  5. const framePage = document.getElementById('framePage')
  6. console.log(framePage.contentWindow.document) //同源的可以获取,非同源的无法获取
  7. }
  8. </script>

2.2 Membatasi Akses Cookie

"Sumber A" tidak dapat mengakses cookie "Sumber B"

  1. <iframe id="baidu" src="http://www.baidu.com" width="500" height="300"></iframe>
  2. <script type="text/javascript" >
  3. // 访问的是当前源的cookie,并不是baidu的cookie
  4. console.log(document.cookie)
  5. </script>

2.3 Batasi Ajax untuk memperoleh data

"Sumber A" dapat mengirimkan permintaan ke "Sumber B", tetapi tidak dapat memperoleh data respons dari "Sumber B".

  1. const url = 'https://www.toutiao.com/hot-event/hot-board/?origin=toutiao_pc'
  2. let result = await fetch(url)
  3. let data = await result.json();
  4. console.log(data)

Catatan: Di antara batasan di atas, pembatasan browser pada akuisisi data Ajax memiliki dampak terbesar, dan sering kali ditemui dalam pengembangan sebenarnya.

3 poin yang perlu diperhatikan

  • 1Pembatasan lintas domain hanya ada di sisi browser, dan tidak ada pembatasan lintas domain di sisi server.
  • 2 Meskipun lintas domain, permintaan Ajax dapat dikeluarkan secara normal, tetapi data respons tidak akan diserahkan kepada pengembang.
  • 3<link> , <script>、<img>...... 这些标签发出的请求也可能跨域,只不过浏览器对标签跨域不做严格限制,对开发几乎无影响

gambar.png

4CORS memecahkan masalah lintas domain Ajax

4.1 Ikhtisar CORS

Nama lengkap CORS: Berbagi Sumber Daya Lintas Asal (Cross-Origin Resource Sharing) adalah seperangkat spesifikasi yang digunakan untuk mengontrol verifikasi browser atas permintaan lintas domain. Server mengikuti spesifikasi CORS dan menambahkan header respons spesifik untuk mengontrol verifikasi browser. Aturan umumnya adalah sebagai berikut:
●Server secara eksplisit menolak permintaan lintas-domain, atau tidak menunjukkannya, dan browser gagal dalam verifikasi.
●Server dengan jelas menunjukkan bahwa permintaan lintas domain diperbolehkan, dan verifikasi browser lolos.
Catatan: Menggunakan CORS untuk menyelesaikan masalah lintas domain adalah cara yang paling ortodoks, dan mengharuskan server menjadi "salah satu milik kita".


4.2CORS menyelesaikan permintaan lintas domain sederhana

Gagasan keseluruhan: Ketika server merespons, ini dengan jelas menyatakan bahwa sumber tertentu diizinkan untuk memulai permintaan lintas domain dengan menambahkan header respons Access-Control-Allow-Origin, dan kemudian browser meneruskannya secara langsung selama verifikasi.

gambar.png

Kode inti sisi server (ambil kerangka kerja ekspres sebagai contoh):

  1. // 处理跨域中间件
  2. function corsMiddleWare(req,res,next){
  3. // 允许 http://127.0.0.1:5500 这个源发起跨域请求
  4. // res.setHeader('Access-Control-Allow-Origin','http://127.0.0.1:5500')
  5. // 允许所有源发起跨域请求
  6. res.setHeader('Access-Control-Allow-Origin','*')
  7. next()
  8. }
  9. // 配置路由并使用中间件
  10. app.get('/',corsMiddleWare,(req,res)=>{
  11. res.send('hello!')
  12. })

4.3 Permintaan sederhana dan permintaan kompleks

CORS akan membagi permintaan menjadi dua kategori: ① permintaan sederhana dan ② permintaan kompleks.

permintaan sederhana

Permintaan yang rumit

✅Metode permintaan (metode) adalah: GET, HEAD, POST

1 bisa berupa permintaan sederhana atau permintaan kompleks.
2 Permintaan kompleks akan secara otomatis mengirimkan permintaan preflight.

✅Bidang header permintaan harus sesuai"Spesifikasi Keamanan CORS"
Catatan singkat: Selama header permintaan tidak diubah secara manual, secara umum header permintaan dapat mematuhi spesifikasi ini.

✅Nilai Tipe Konten dari header permintaan hanya dapat berupa tiga nilai berikut:
●teks/polos
●multipart/formulir-data
●aplikasi/x-www-form-urlencoded

Mengenai permintaan pra-penerbangan:

  • 1Waktu pengiriman: Permintaan preflight dikirim sebelum permintaan lintas domain yang sebenarnya dan secara otomatis dimulai oleh browser.
  • 2 Fungsi utama: digunakan untuk mengonfirmasi dengan server apakah akan mengizinkan permintaan lintas domain berikutnya.
  • 3Proses dasar: Pertama, mulai permintaan OPTIONS. Jika lolos pra-pemeriksaan, lanjutkan untuk memulai permintaan lintas domain yang sebenarnya.
  • 4 Isi header permintaan: Permintaan preflight OPTIONS biasanya berisi header permintaan berikut:

Judul permintaan

arti

Asal

Sumber permintaan

Metode Permintaan Kontrol Akses

Metode HTTP sebenarnya yang diminta

Header Permintaan Kontrol Akses

Header khusus yang digunakan dalam permintaan sebenarnya (jika ada)

4.4CORS menyelesaikan permintaan lintas domain yang kompleks

1 Langkah pertama: Server terlebih dahulu meneruskan permintaan preflight browser. Server perlu mengembalikan header respons berikut:

tajuk tanggapan

arti

Akses-Kontrol-Izinkan-Asal

sumber yang diperbolehkan

Metode-Izin-Kontrol-Akses

metode yang diizinkan

Akses-Kontrol-Izinkan-Header

Header khusus yang diizinkan

Akses-Kontrol-Usia-Maks

Waktu cache hasil untuk permintaan preflight (opsional)

gambar.png

2 Langkah 2: Tangani permintaan lintas domain yang sebenarnya (sama seperti Anda menangani permintaan lintas domain sederhana)

gambar.png

Kode inti server:

  1. // 处理预检请求
  2. app.options('/students', (req, res) => {
  3. // 设置允许的跨域请求源
  4. res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500')
  5. // 设置允许的请求方法
  6. res.setHeader('Access-Control-Allow-Methods', 'GET')
  7. // 设置允许的请求头
  8. res.setHeader('Access-Control-Allow-Headers', 'school')
  9. // 设置预检请求的缓存时间(可选)
  10. res.setHeader('Access-Control-Max-Age', 7200)
  11. // 发送响应
  12. res.send()
  13. })
  14. // 处理实际请求
  15. app.get('/students', (req, res) => {
  16. // 设置允许的跨域请求源
  17. res.setHeader('Access-Control-Allow-Origin', 'http://127.0.0.1:5500')
  18. // 随便设置一个自定义响应头
  19. res.setHeader('abc',123)
  20. // 设置允许暴露给客户端的响应头
  21. res.setHeader('Access-Control-Expose-Headers', 'abc')
  22. // 打印请求日志
  23. console.log('有人请求/students了')
  24. // 发送响应数据
  25. res.send(students)
  26. })

4.5 Gunakan perpustakaan cors untuk menyelesaikan konfigurasi dengan cepat

Dalam konfigurasi di atas, Anda perlu mengonfigurasi header respons sendiri, atau Anda perlu mengenkapsulasi middleware secara manual Dengan pustaka cors, Anda dapat menyelesaikan konfigurasi dengan lebih nyaman.

●Pasang kor

npm i cors

●Kor konfigurasi sederhana

app.use(cors())

●Konfigurasi kors sepenuhnya

  1. // cors中间件配置
  2. const corsOptions = {
  3. origin: 'http://127.0.0.1:5500', // 允许的源
  4. methods: ['GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS'], // 允许的方法
  5. allowedHeaders: ['school'], // 允许的自定义头
  6. exposedHeaders: ['abc'], // 要暴露的响应头
  7. optionsSuccessStatus: 200 // 预检请求成功的状态码
  8. };
  9. app.use(cors(corsOptions)); // 使用cors中间件

Secara default, js tidak dapat mengakses header respons yang disetel oleh backend dan perlu diekspos oleh backend.

5JSONP memecahkan masalah lintas domain

Ikhtisar 1JSONP: Penggunaan JSONP<script>标签可以跨域加载脚本,且不受严格限制的特性,可以说是程序员智慧的结晶,早期一些浏览器不支持 CORS 的时,可以靠 JSONP 解决跨域。


2Proses dasar:

  • ○Langkah pertama: Klien membuat a<script>标签,并将其src属性设置为包含跨域请求的 URL,同时准备一个回调函数,这个回调函数用于处理返回的数据。
  • ○Langkah 2: Setelah menerima permintaan, server merangkum data dalam fungsi panggilan balik dan mengembalikannya.
  • ○Langkah 3: Fungsi panggilan balik klien dipanggil, dan data diteruskan ke fungsi panggilan balik dalam bentuk parameter.

3Ilustrasi:

gambar.png

4 contoh kode:

  1. <button onclick="getTeachers()">获取数据</button>
  2. <script type="text/javascript" >
  3. function callback(data){
  4. console.log(data)
  5. }
  6. function getTeachers(url){
  7. // 创建script元素
  8. const script = document.createElement('script')
  9. // 指定script的src属性
  10. script.src= 'http://127.0.0.1:8081/teachers'
  11. // 将script元素添加到body中触发脚本加载
  12. document.body.appendChild(script)
  13. // script标签加载完毕后移除该标签
  14. script.onload = ()=>{
  15. script.remove()
  16. }
  17. }
  18. </script>

5jQuery mengenkapsulasi jsonp

?callback=?' adalah format tetap dan akan diuraikan secara otomatis

  1. $.getJSON('http://127.0.0.1:8081/teachers?callback=?',(data)=>{
  2. console.log(data)
  3. })

6Konfigurasi proksi untuk menyelesaikan masalah lintas domain

6.1 Konfigurasikan sendiri server proxy

Tidak ada masalah lintas domain antar server. Anda perlu menggunakan express untuk memulai sumber daya statis untuk memastikan bahwa server dan halaman Anda berada di asal yang sama.

  1. // 启动静态资源 让服务器跟页面同一个源
  2. app.use(express.static("./public"));

Konfigurasikan proxy dengan http-proxy-middleware

  1. const { createProxyMiddleware } = require('http-proxy-middleware');
  2. app.use('/api',createProxyMiddleware({
  3. target:'https://www.toutiao.com',
  4. changeOrigin:true,
  5. pathRewrite:{
  6. '^/api':''
  7. }

 

keuntungan:

  • Fungsi yang kaya: http-proxy-middleware menyediakan banyak pilihan konfigurasi untuk memenuhi berbagai kebutuhan proxy.
  • Beberapa proxy dapat dikonfigurasi secara fleksibel: Beberapa server proxy dapat dikonfigurasi, sesuai dengan jalur antarmuka yang berbeda.
  • Dapat mencegat permintaan: Permintaan dapat dicegat dan dimodifikasi melalui fungsi pemrosesan khusus.

kekurangan:

  • Konfigurasinya relatif rumit: Anda perlu memahami aturan konfigurasi dan parameter perpustakaan http-proxy-middleware.
  • Tidak cocok untuk lingkungan produksi: http-proxy-middleware terutama digunakan di lingkungan pengembangan dan tidak cocok untuk lingkungan produksi.

adegan yang akan digunakan:

  • Cocok untuk proyek front-end menggunakan alat build apa pun dan berfungsi dengan server pengembangan apa pun.
  • Cocok untuk skenario di mana beberapa server proxy perlu dikonfigurasi secara fleksibel.
  • Cocok untuk skenario ketika permintaan perlu disadap dan dimodifikasi.

6.2 Gunakan Nginx untuk membangun server proxy

Ide keseluruhannya: biarkan nginx memainkan dua peran, baik sebagai server konten statis dan sebagai server proxy.

Ubah konfigurasi nginx sebagai berikut. Perhatikan bahwa direktori root nginx sebaiknya bukan drive C.

  1. # 配置nginx根目录
  2. location / {
  3. root D:dist;
  4. index index.html index.htm;
  5. }
  6. # 配置代理
  7. location /dev/ {
  8. # 设置代理目标
  9. proxy_pass http://sph-h5-api.atguigu.cn/;
  10. }

2 Ubah proyek front-end sehingga semua permintaan diteruskan ke /dev, lalu dikemas ulang

  1. const request = axios.create({
  2. baseURL:'/dev',
  3. timeout:10000
  4. })

Kemudian langsung akses server nginx. Misalnya jika nginx berjalan pada port 8099, akses

http://localhost:8099

Kemudian Anda akan menemui masalah refresh 404, tambahkan konfigurasi nginx untuk menyelesaikannya

  1. # 配置nginx根目录
  2. location / {
  3. root D:dist;
  4. index index.html index.htm;
  5. try_files $uri $uri/ /index.html; # 解决刷新404
  6. }
  7. # 配置代理
  8. location /dev/ {
  9. # 设置代理目标
  10. proxy_pass http://sph-h5-api.atguigu.cn/;
  11. }

Menambahkan dua "/" ini menghilangkan dev

6.3 Membangun server dengan bantuan scaffolding

1. Gunakan file vue.config.js untuk mengkonfigurasi proxy:

Buat file vue.config.js di direktori root proyek Vue dan tambahkan kode berikut:

  1. module.exports = {
  2. devServer: {
  3. proxy: {
  4. '/api': {
  5. target: 'http://api.example.com',
  6. changeOrigin: true,
  7. pathRewrite: {
  8. '^/api': ''
  9. }
  10. }
  11. }
  12. }
  13. }

Dalam kode di atas, kami menggunakandevServer Item konfigurasi untuk mengkonfigurasi server proxy.di dalamproxyProperti digunakan untuk mengonfigurasi aturan proxy,/apiMenunjukkan jalur antarmuka yang memerlukan proksi.targetAtribut mewakili alamat server target proxy,changeOriginAtribut menunjukkan apakah akan mengubah alamat sumber permintaan.pathRewriteProperti yang digunakan untuk mengganti jalur yang diminta.

keuntungan:

  • Konfigurasi sederhana: Menggunakan konfigurasi proxy webpack-dev-server, Anda hanya perlu melakukan konfigurasi sederhana di file konfigurasi webpack.
  • Fungsionalitas yang komprehensif: webpack-dev-server menyediakan banyak opsi konfigurasi untuk memenuhi sebagian besar kebutuhan proxy.
  • Dapat mencegat permintaan: Permintaan dapat dicegat dan dimodifikasi melalui fungsi pemrosesan khusus.

kekurangan:

  • Server perlu di-restart: Setelah konfigurasi diubah, webpack-dev-server perlu di-restart agar dapat diterapkan.
  • Tidak cocok untuk lingkungan produksi: webpack-dev-server terutama digunakan di lingkungan pengembangan dan tidak cocok untuk lingkungan produksi.

adegan yang akan digunakan:

  • Sangat cocok untuk proyek front-end yang dibangun menggunakan webpack dan memulai server pengembangan melalui webpack-dev-server.
  • Cocok untuk skenario yang memerlukan konfigurasi proxy sederhana dan tidak perlu sering mengubah konfigurasi proxy.