上次研究了一下利用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(); });
最终调通了。