跨域訪問CORS
上次研究了一下利用Heroku app寫了一個webservice,供Salesforce Lightning fetch通過apex呼叫,後來由於只是讀取資料,所以提出要改成直接在js裡呼叫webserivce, 不通過Apex, 這裡就涉及到一個跨域訪問的問題。
對大佬而言這麼簡單的問題我研究了3天,簡直蝸牛了,不過還好最終搗鼓通了。
起初試了很多方法遇到了一個Preflight Request,翻譯過來叫什麼預起飛請求, 說的是相對於普通的請求,“預起飛”請求需要在實際請求(比如POST)的同時,瀏覽器會先向伺服器傳送一個OPTION請求用來驗證請求資料對訪問資料是否安全,確認安全後實際的請求才會被髮出並處理。因此我遇到一個錯誤,伺服器端log顯示, OPTION 請求返回200, ok, 但是實際POST請求卻總是報錯 “unexpected token o in json at position express” , 這種情況下,一種解決方法說可以安裝 cors 包來解決(cors 包會自動處理OPTIONS請求), 但是我試了很多次都不好使,放棄了; 還有種方式就是改變Content-Type 型別由 “Application/json” 變成 “text/plain”, 使得請求轉變成普通型別,避免預起飛(Preflight),這種方式成功了。
https://dev.to/effingkay/cors-preflighted-requests--options-method-3024
然而之後又產生了一個新的錯誤說"Refused to connect to because it violates the following Content Security Policy directive: "connect-src 'self' example1.com example2.com", 查其原因是因為Content Security Policy 中connectSrc directive配置了允許訪問的源,這裡我用了 helmet-csp package。
https://helmetjs.github.io/docs/csp/
var csp = require('helmet-csp');
app.use(csp({ directives: { defaultSrc: ["'self'"], scriptSrc: ["'self'", "'unsafe-inline'"], reportUri: '/report-violation', connectSrc:[ "'self'"], objectSrc: ["'none'"], upgradeInsecureRequests: true, workerSrc: false }, reportOnly: true }));
然而之後又產生了一個新的錯誤說是“Access to fetch at from origin has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.” 查明原因是因為,瀏覽器並不知道其訪問的內容是否安全,CORS策略中有個Header Access-Control-Allow-Origin, 伺服器端
需要在響應中新增此Header以告知瀏覽器該返回響應中的資料對於瀏覽器當前域是允許的,否則瀏覽器會阻止訪問。
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
app.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); // update to match the domain you will make the request from res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); next(); });
最終調通了