・環境
クライアントオリジン→http://127.0.0.1:5500
サーバーオリジン→http://localhost:3000
・解決したいこと
deleteメソッドのcorsエラーを解消したいです。
management.htmlで全てのユーザーが表示された後、それぞれのユーザーの編集ボタンを押下するとsearch.htmlへ飛び、選択した単体のユーザーが表示されます。そこでユーザーを削除するボタンを押下する処理でcorsエラーとなってしまいます。なぜかpostmanでは削除できました、、
・エラー内容
Access to fetch at 'http://localhost:3000/api/v1/users/41' from origin 'http://127.0.0.1:5500' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
users.js:82 DELETE http://localhost:3000/api/v1/users/41 net::ERR_FAILED
deleteUser @ users.js:82
(anonymous) @ index.js:24。
users.js:102 Uncaught (in promise) TypeError: Failed to fetch
・試したこと
originが異なるのでサーバーからのレスポンスヘッダーに('Access-Control-Allow-Origin', ' * ')を付与しましたが解決できず、
OPTIONSでdeleteメソッドを許容しているか確認したところ、以下のレスポンスとなりました。
$ curl -X OPTIONS "http://localhost:3000/api/v1/users/1" -v
- Trying ::1...
- TCP_NODELAY set
- Connected to localhost (::1) port 3000 (#0)
OPTIONS /api/v1/users/1 HTTP/1.1
Host: localhost:3000
User-Agent: curl/7.64.1
Accept: /
< HTTP/1.1 200 OK
< X-Powered-By: Express
< Allow: GET,HEAD,PUT,DELETE
< Content-Type: text/html; charset=utf-8
< Content-Length: 19
< ETag: W/"13-dU6690u+/fZ3lEqFItU6CiBI3Wo"
< Date: Thu, 10 Jun 2021 05:30:06 GMT
< Connection: keep-alive
<
- Connection #0 to host localhost left intact
GET,HEAD,PUT,DELETE* Closing connection 0
こちらも問題なさそうだったので後は何だろうと類似スレッドを見ていたら、deleteではプリフライトリクエストがdelete実行前に走り、これに該当した場合も形式上corsエラーとなるようですが原因が思い浮かびません。
何か参考になるアドバイスをいただけないでしょうか。よろしくお願いいたします。
javaScript
1app.js 2 3const express = require('express'); 4const app = express(); 5const dbPath = "app/db/database.sqlite3" 6const path = require('path') 7 8const sqlite3 = require('sqlite3') 9 10app.use(express.urlencoded({extended: true})) 11app.use(express.json()) 12app.use(express.static(path.join(__dirname, 'public'))) 13 14app.get('/api/v1/users', (req, res) => { 15 const db = new sqlite3.Database(dbPath) 16 res.set('Access-Control-Allow-Origin', '*' ) 17 18 db.all('SELECT * FROM users', (err, rows) => { 19 res.json(rows) 20 }) 21 db.close() 22}) 23 24 25app.get('/api/v1/users/:id', (req, res) => { 26 const db = new sqlite3.Database(dbPath) 27 const id = req.params.id 28 res.set('Access-Control-Allow-Origin', '*' ) 29 30 db.get(`SELECT * FROM users WHERE id = ${id}`, (err, row) => { 31 res.json(row) 32 }) 33 db.close() 34}) 35 36 37const run = async (sql, db, res, message) => { 38 return new Promise((resolve, reject) => { 39 db.run(sql, (err) => { 40 if (err) { 41 res.status(500).send(err) 42 return reject() 43 } else { 44 res.json({message: message}) 45 return resolve() 46 } 47 }) 48 }) 49} 50 51app.delete('/api/v1/users/:id', async (req, res) => { 52 res.set('Access-Control-Allow-Origin', '*' ) 53 54 const db = new sqlite3.Database(dbPath) 55 const id = req.params.id 56 57 58 await run (`DELETE FROM users WHERE id = ${id}`, 59 db, 60 res, 61 "ユーザーを削除しました" 62 ) 63 db.close() 64}) 65 66const port = process.env.PORT || 3000; 67app.listen(port); 68console.log("Listen on port: " + port)
javascript
1users.js 2 3const usersModules = (() => { 4 const BASE_URL = "http://localhost:3000/api/v1/users" 5 const headers = new Headers() 6 7 headers.set('Content-Type', 'application/json') 8 9 return { 10 setExistingUser: async (uid) => { 11 const res = await fetch(BASE_URL + '/' + uid) 12 const resJson = await res.json() 13 14 let body = `<tr> 15 <td>${resJson.id}</td> 16 <td>${resJson.name}</td> 17 <td>${resJson.kana}</td> 18 <td>${resJson.addess}</td> 19 <td>${resJson.company}</td> 20 <td>${resJson.department}</td> 21 <td>${resJson.phoneNumber}</td> 22 <td>${resJson.post}</td> 23 <td>${resJson.post2}</td> 24 <td>${resJson.contents}</td> 25 </tr>` 26 27 document.getElementById('search-list').insertAdjacentHTML('beforeend', body) 28 }, 29 deleteUser: async (uid) => { 30 const res = await fetch(BASE_URL + '/' + uid, { 31 method: "DELETE", 32 headers: headers, 33 }) 34 const resJson = await res.json() 35 alert(resJson.message) 36 window.location.href = '/' 37 } 38 }()
javascript
1index.js 2 3const indexModule = (() => { 4 const path = window.location.pathname 5 6 switch(path) { 7 case '/app/public/management.html': 8 return usersModules.fetchAllUsers() 9 10 case '/app/public/search.html': 11 const uid = window.location.search.split('?uid=')[1] 12 13 document.getElementById('delete-btn').addEventListener('click', () => { 14 return usersModules.deleteUser(uid) 15 }) 16 return usersModules.setExistingUser(uid) 17 } 18})()
html
1 2management.html 3 4<!DOCTYPE html> 5<html lang="ja"> 6<head> 7 <meta charset="UTF-8"> 8 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 9 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 10 <title>HP管理ページ</title> 11</head> 12<body> 13 <h1>お問い合わせ一覧</h1> 14 <label for="search">ユーザー名で検索</label> 15 <input type="text" id="search"> 16 <button id="searching-btn">検索</button> 17 18 <table> 19 <thead> 20 <tr> 21 <td>id</td> 22 <td>名前</td> 23 <td>かな</td> 24 <td>メールアドレス</td> 25 <td>会社名</td> 26 <td>部署名</td> 27 <td>電話番号</td> 28 <td>住所</td> 29 <td>建物/ビル名</td> 30 <td>お問い合わせ内容</td> 31 <td>管理</td> 32 </tr> 33 </thead> 34 <tbody id="users-list"> 35 36 </tbody> 37 </table> 38 <script src="js/users.js" defer></script> 39 <script src="js/index.js" defer></script> 40</body> 41</html>
html
1 2search.html 3 4<!DOCTYPE html> 5<html lang="ja"> 6<head> 7 <meta charset="UTF-8"> 8 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 9 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 10 <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous"> 11 <title>HP管理ページ</title> 12</head> 13<body> 14 <h1>お問い合わせ一覧</h1> 15 <div class="container-fluid d-flex"> 16 <div class="title"> 17 <label for="search">ユーザー名で検索</label> 18 <input type="text" id="search"> 19 <button id="search-btn">検索</button> 20 </div> 21 <div class="menu d-flex ml-5"> 22 <p>このユーザーに 23 <button class="btn btn-sm btn-danger" id="edit-btn">返信する</button> 24 </p> 25 <p class="ml-5">このユーザーを 26 <button class="btn btn-sm btn-secondary" id="delete-btn">削除する</button> 27 </p> 28 </div> 29 </div> 30 31 <table> 32 <thead> 33 <tr> 34 <td>id</td> 35 <td>名前</td> 36 <td>かな</td> 37 <td>メールアドレス</td> 38 <td>会社名</td> 39 <td>部署名</td> 40 <td>電話番号</td> 41 <td>住所</td> 42 <td>建物/ビル名</td> 43 <td>お問い合わせ内容</td> 44 45 </tr> 46 </thead> 47 <tbody id="search-list"> 48 49 </tbody> 50 </table> 51 <script src="js/users.js" defer></script> 52 <script src="js/index.js" defer></script> 53</body> 54</html>
あなたの回答
tips
プレビュー