on 12-06-2023 12:56 PM
Hello Experts,
I've a multi target application which has the following modules:
1) SAPUI5 App - frontend
2) Node.js app with express server and 'sap-cf-axios' (acts as middleware)
3) Standalone approuter (the SAPUI5 is embedded in the resources and has entry to protect the service)
Application flow: UI5 calls node which calls service (on-premise destination using cloud connector)
xs-app.json of the approuter
{
"welcomeFile": "/app/webapp/index.html",
"authenticationMethod": "route",
"sessionTimeout": 30,
"logout": {
"logoutEndpoint": "/do/logout",
"logoutPage": "/"
},
"routes": [
{
"source": "^/app/(.*)$",
"target": "$1",
"localDir": "resources",
"authenticationType": "xsuaa"
},
{
"source": "^/srv/(.*)$",
"target": "$1",
"destination": "srv-api",
"authenticationType": "xsuaa"
}
]
UI5 url works:
url: <my-cf-approuter>/app/webapp/index.html
node js code (without destination - also works)
url: <my-cf-approuter>/srv/hello
const passport = require('passport');
const xsenv = require('@sap/xsenv');
const JWTStrategy = require('@sap/xssec').JWTStrategy;
const express = require('express');
const services = xsenv.getServices({ uaa:'project1-xsuaa' });
const app = express();
passport.use(new JWTStrategy(services.uaa));
app.use(passport.initialize());
app.use(passport.authenticate('JWT', { session: false }));
const handleHello = async (req, res) => {
console.log("-->"+req.user.id)
res.send("Hello " + req.user.id);
//res.send("Hello");
}
app.get("/hello", handleHello);
const port = process.env.PORT || 3000;
app.listen(port, function () {
console.log('myapp listening on port ' + port);
});
The node.js app uses a destination called SAP_GWD for trying to connect to the on-premise backend (system is configured in both BTP & Cloud Connector by the BASIS team using basic authenticaton) .
The code that uses the destination does not work:
url: <my-cf-approuter>/srv/get
const passport = require('passport');
const xsenv = require('@sap/xsenv');
const JWTStrategy = require('@sap/xssec').JWTStrategy;
const express = require('express');
const SapCfAxios = require("sap-cf-axios").default;
const services = xsenv.getServices({ uaa:'project1-xsuaa' });
const app = express();
passport.use(new JWTStrategy(services.uaa));
app.use(passport.initialize());
app.use(passport.authenticate('JWT', { session: false }));
const axios1 = SapCfAxios("SAP_GWD");
const handleGet = async (req, res) => {
console.log("Calling destination"); // this line is written to the log
const response = await axios1({
method: "GET",
url: "/sap/opu/data/my_service...",
headers: {
accept: "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8"
}
});
console.log(response);
res.send(response.data);
app.get("/get", handleGet);
const port = process.env.PORT || 3000;
app.listen(port, function () {
console.log('myapp listening on port ' + port);
});
The error log entry in the approuter is:
VError: error while forwarding request to ***/get: socket hang up correlation_id = ***
Attached also mta.yaml file which uses the destination service & the connectivity service
ID: prj1
_schema-version: '3.1'
version: 1.0.0
description: "Project 1"
modules:
# -------------------- SERVICE -----------------------------
- name: project1-service
# ------------------------------------------------------------
type: nodejs
path: srv
build-parameters:
ignore:
- 'default-*.json'
- .env
- '*node_modules*'
- package-lock.json
provides:
- name: srv-api
properties:
srv-url: ${default-url}
requires:
- name: project1-xsuaa
- name: project1-destination-service
- name: project1-connectivity-service
# ------------------- UI ------------------------
- name: project1-app
# ------------------------------------------------------------
type: html5
path: app
build-parameters:
supported-platforms: []
# -------------------- APPROUTER -----------------------------
- name: project1-approuter
# ------------------------------------------------------------
type: nodejs
path: approuter
requires:
- name: project1-xsuaa
- name: srv-api
group: destinations
properties:
name: srv-api # must be used in xs-app.json as well
url: ~{srv-url}
forwardAuthToken: true
- name: project1-destination-service
- name: project1-connectivity-service
build-parameters:
requires:
- name: project1-app
artifacts:
- ./*
target-path: resources
resources:
# ------------------------------------------------------------
- name: project1-xsuaa
# ------------------------------------------------------------
type: org.cloudfoundry.managed-service
parameters:
service: xsuaa
service-plan: application
path: ./xs-security.json
config:
xsappname: 'project1-${space}'
role-collections:
- name: 'TechUserPOC-${space}'
description: Technical User POC
role-template-references:
- $XSAPPNAME.TechUserPOC
# ------------------------------------------------------------
- name: project1-destination-service
# ------------------------------------------------------------
type: org.cloudfoundry.managed-service
parameters:
service: destination
service-plan: lite
# ------------------------------------------------------------
- name: project1-connectivity-service
# ------------------------------------------------------------
type: org.cloudfoundry.managed-service
parameters:
service: connectivity
service-plan: lite
Please reply if you need any more info.
How can I solve this issue?
Regards,
Omri
I would suggest you either use SAP Cloud SDK for your backend requests as it would solve the issue to call the backend via destination / connectivity service.
Or it might be even easier to use CAP as it seems that your backend is an OData Service.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi,
Tried to use SAP Cloud SDK minimal test example - still no luck )-:
import { executeHttpRequest } from '@sap-cloud-sdk/http-client';
import { getDestination } from '@sap-cloud-sdk/connectivity';
async function minimalTest() {
const destination = await getDestination({
destinationName: YOUR_DESTINATION_NAME
});
if (destination) {
destination.authTokens?.forEach(authToken => {
if (authToken.error) {
throw new Error(`Error in authToken ${authToken.error}`);
}
});
} else {
throw new Error('Destination is undefined.');
}
console.log('Destination Retrieved.');
const response = await executeHttpRequest(destination, {
method: 'get',
url: YOUR_SERVICE_URL
});
if (!response.data) {
throw new Error('No data returned');
}
console.log('Data Retrieved.');
}
Works with Northwind (Proxy type - Internet)
Does not work with SAP_GWD (Proxy type - OnPremise)
I get 'Destination Retrieved' in the log but no other messages after it (no data nor exception).
Attached also SAP_GWD Connection settings:
I guess there is an issue with the connectivity service.
Since I'm using SAP Standard code I'll open a case in SAP but before, any other ideas?
Best Regards,
Omri
Maybe you try with my sample app: HTML5UserAPIforCF
Hi Gergor,
Your code didn't work either on my environment.
I've manage to debug my code remotely and saw a 'clearer' error message:
Timed out waiting for tunnel to open for tunnelId account:///<<account number>>
From my understanding something is blocked between CF and OnPremise (maybe on Firewall level)
Also, I guess deploy and curl work from BAS since BAS has its own reverse proxy.
Regards,
Omri
Hi,
You wrote: can you check in the subaccount where you've deployed the application if the Cloud Connector is actually connected?
How can I test it? the tests I did were from BAS/BTP side to cloud connector (I don't have access to the cloud connector and need to ask the BASIS team).
Attached screenshot of the Cloud Connectors screen from the BTP.
When I did curl (from BAS) to the OData service I asked them to check and they saw the OData payload in the logs (from CF runtime there is no payload nor error in the Cloud Connector logs).
I also sent the BASIS team the following link for checking Firewall settings
Some more info: up to now the organization uses BAS for developing/deploying UI5 (frontend apps) to OnPremise system (SAP_GWD).
My POC is for developing full-stack app that will be running on CF and will use the OnPremise system.
Does the fact the developing/deploying process from BAS (that uses the destination) works and CF runtime code that uses the same destination doesn't work mean something?
Am I right by assuming that BAS has some 'special' proxy which is different from the CF runtime for using the connectivity service?
Finally, your help and patience are much appreciated!
Regards
Omri
I still urge you to test with HTML5UserAPIforCF. Because your code sample is not using any SAP Supported library. If a deployment from BAS in the same subaccount is possible, but connecting from an UI5 app running in an approuter that has bindings to destination and connectivity service isn't then I think you should contact SAP support to help you.
Hi Gregor,
As I wrote, I started with sap-cf-axios (which is not standard) and moved to SAP cloud SDK (using Minimal Example) and also your sample code from the github repo).
Also, In some of my tests I removed the UI5/Approuter and tested only the service (it was easy to check because the destination uses Basic Authentication and not JWT).
In all three cases I got the same error (503) and couldn't connect to on-premise destination (internet destination works for all three cases).
I already contacted SAP and opened a case and I'm waiting for reply (I'll update this thread).
Regards,
Omri
User | Count |
---|---|
72 | |
8 | |
8 | |
6 | |
6 | |
6 | |
5 | |
5 | |
5 | |
5 |
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.