Quicklinks:
Proxy Server
Quick Ref
Sample Code
Dear friends, please try to stay calm when you see this error message:
Access to XMLHttpRequest at 'file://.../webapp/manifest.json' ... has been blocked by CORS policy
I know what you're thinking:
Why is life so difficult? I only wanted to open my UI5 app - it is only a very silly first test app
No reason to get angry…
Why not??? How can you stay calm?
Because I found how to solve
Ahh, and before that?
I was sooooo angry
Aha...
So angry that I had to find the solution
In google...
I found lots of many of questions, but no satisfying answers
And what did the non-satisfying answer say?
It said e.g. to use a proxy server
And how to do that?
Exactly, that’s the point.
Can we learn it here...?
Please go ahead, read this blog, it is for free and the code is simple
Some background information about the problem?
That can be found nicely explained in the internet, I don’t want to copy that…
Overview
We create a very small ui5 app, open it in browser and see the behated error
Then we create a proxy server, open our app with it - and see the beloved ui
Note:
If you want to use app router, see
this blog
Prerequisites
To reduce the effort, we choose
Node.js to create the server
So you need to have
Node.js installed on your machine
See
here for little help, no need to be familiar with node.js development
Step 1: Create UI5 App
In this tutorial, we're creating a little silly app, using the silly sample code in
appendix, but you can also use your own silly application
The only condition: it must fail with above error.
To create a new application, we create a root folder, e.g.
C:\tmp_cors_1
Inside that root folder, we create a folder
webapp
The project structure looks like this:
This folder contains the files, which we copy from the
appendix section
As mentioned, it is just a silly app displaying some silly text
Test it: open the app
To open a web app, we usually just double-click the
index.html file, or drag & drop it to a browser window
However, if we try to open our silly little app, we get an empty page and the developer tools give the error message:
Access ... has been blocked by CORS policy
The error message gives us a little hint: it says that CORS is (only) supported for "http protocol"
Solution: we need to serve our app by a little silly proxy server
Step 2: Create Proxy Server
Such proxy server can be very easily created with
Node.js and
express
Summarizing:
We create a node app which starts a server.
That server does nothing than to serve a static file
That’s all
Now guess WHICH file will be that static file in our example…???
It will be our index.html and all other files in webapp folder
To add one little silly requirement:
We want that the proxy server should be located in a separate folder, not in the application folder
As such, we create a folder with name
proxyserver, located inside our root project folder
tmp_cors_1 next to our
webapp
Inside the proxyserver folder, we create 2 files:
package.json
and
app.js
Refer to screenshot for structure and content:
package.json
We paste the following content into the
package.json file
{
"dependencies": {
"express": "^4.17.1"
}
}
This minimalistic content just defines a dependency to the
express module, which is responsible for easily creating a server
To install the dependency:
Open command prompt, navigate to
proxyserver folder and invoke
npm install --save
This will create a folder
node_modules and copy all required libraries into it
app.js
The content of the application file
const express = require('express');
const app = express();
const path = require('path');
const parentFolderPath = path.resolve(__dirname, '..')
// add middleware to serve static file
app.use(express.static(path.join(parentFolderPath, 'webapp')))
// start the server
app.listen(8080, () => {
console.log('Serving file "../webapp/index.html". Open at "localhost:8080". Use Ctr+C to shutdown');
})
Note that we aren’t defining any endpoint.
No
app.get('/productList')
or similar
We just don’t need it.
Express is doing that for us
This is the relevant line:
app.use(express.static(path.join(parentFolderPath,'webapp')))
We’re using express-middleware:
app.use(...)
And we’re using convenience functionality offered by express, to serve static content:
express.static(someFolder)
The
static statement expects a folder as first param
We don’t need to pass our static file, because
index.html is served by default
See
docu
We could place our
app.js next to the
webapp folder, then we could just write
express.static(someFolder)
making things easy
But that would be little ugly, to have proxyserver logic mixed with the frontend logic
That’s why we wanted to have a separate folder for the proxyserver
And so we need one more line of code, to compute the path to the webapp folder
We step one level up:
const parentFolderPath = path.resolve(__dirname, '..')
then one level down
path.join(parentFolderPath, 'webapp')
Note:
One big advantage of this little additional effort is:
It makes it easy to reuse the proxyserver
We can just copy & paste the proxyserver folder next to any other webapp folder
If you have deeper nested folder structure, just add additional folder to the join statement:
path.join(parentFolderPath,'projectfolder', 'webapp')
Finally, let the server start up and listen at a port of our choice
app.listen(8080, () => {
console.log('Serving file "../webapp/index.html". Open at "localhost:8080". Use Ctr+C to shutdown');
})
After saving the file, we can start the server
We open command prompt and step into the proxyserver folder
Then, to run our app, we execute the following command:
node app.js
As a result we can see our log output
Now we’re ready to open our web application
Test it: open the app
We open our browser and type this address:
localhost:8080
As a result, we can see our beautiful (but silly) app UI:
Our browser screen is not (fully) empty and there's (almost) no error in the log
That’s it.
We can now work on our app UI. Whatever change we do in the UI, we don’t need to restart the server, only refresh (or reload) the browser
To stop the server, we press
Ctrl+ C in the command prompt.
Summary
In this little silly tutorial, we’ve learned how to create a little server
It is used to host our ui5 application
Like that, our app runs on a server
This solves CORS error
However, I know that you will run into more CORS errors
How do you know?
I know it, because that happened to me
You were angry...?
Yes...For that reason, I’m already preparing the next blog
Let me finish, then I'll prepare the error
Stay tuned
😉
Where is it?
Thanks for your patience, it is finally
published
Links
https://nodejs.org/en/
https://www.npmjs.com/package/express
http://expressjs.com/
http://expressjs.com/en/starter/static-files.html
Quick Reference
To run your ui5 app locally, on a local server, created with
node.js:
- Create folder (next to your app) with 2 files:
package.json: define dependency, then run
npm install
app.json: server code to serve static file
- Start the node server with
node app.js
- Open browser at
localhost:8080 to see your app
Appendix: Sample Project Files
For your convenience, see the project structure again:
UI5 App
The folder structure:
C:\tmp_cors_1
webapp
App.view.xml
webapp
Component.js
index.html
manifest.json
The content of the files:
App.view.xml
<mvc:View xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc">
<App id="app">
<pages>
<Page title="List of Products">
<content>
<Title level="H1" text="List of Products coming soon" />
</content>
</Page>
</pages>
</App>
</mvc:View>
Component.js
sap.ui.define(["sap/ui/core/UIComponent"],
function (UIComponent) {
return UIComponent.extend("com.local.prodapp.Component", {
metadata : {
manifest: "json"
},
init : function () {
UIComponent.prototype.init.apply(this, arguments);
},
});
});
index.html
<!DOCTYPE html>
<html>
<head>
<script id="sap-ui-bootstrap"
src="https://ui5.sap.com/resources/sap-ui-core.js"
data-sap-ui-theme="sap_belize"
data-sap-ui-resourceroots='{"com.local.prodapp": "./"}'
data-sap-ui-oninit="module:sap/ui/core/ComponentSupport">
</script>
</head>
<body class="sapUiBody" id="content">
<div data-sap-ui-component data-name="com.local.prodapp" ></div>
</body>
</html>
manifest.json
{
"sap.ui5": {
"rootView": {
"viewName": "com.local.prodapp.App",
"type": "XML"
},
"dependencies": {
"libs": {
"sap.ui.core": {},
"sap.m": {}
}
}
}
}
Proxyserver App
The folder structure:
C:\tmp_cors_1
proxyserver
app.js
package.json
The content of the files:
package.json
{
"dependencies": {
"express": "^4.17.1"
}
}
app.js
const express = require('express');
const app = express();
const path = require('path');
const parentFolderPath = path.resolve(__dirname, '..')
// add middleware to serve static file
app.use(express.static(path.join(parentFolderPath, 'webapp')))
// start the server
app.listen(8080, () => {
console.log('Serving file "../webapp/index.html". Open at "localhost:8080". Use Ctr+C to shutdown');
})