Skip to Content
Technical Articles

UI5: solving CORS issue – during local development – with proxy server

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');
})

 

 

 

4 Comments
You must be Logged on to comment or reply to a post.