Set Cache Control in request header doesn't work - http

According to this
The "max-age" request directive indicates that the client is unwilling
to accept a response whose age is greater than the specified number of
seconds
So I tried setting up a small app to test it out. I set the Cache-Control: 'max-age=5' in the request and Cache-Control: 'max-age=10' in the response. If I understand the above sentence correctly, every request I make after 5 seconds should receive a brand new response. But after 5 seconds, I still receive the "old response". Am I missing anything?
Here are code:
Client:
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button onclick="onClick()">
Fetch
</button>
<div class="response-container">
</div>
<script>
const onClick = async () => {
const response = await fetch('http://localhost:3000/hello', {
headers: {
'Cache-Control': 'max-age=5'
}
});
const result = await response.json();
console.log('result', result)
// create a div and append to div with class .response-container
const div = document.createElement('div');
div.innerHTML = result.message;
document.querySelector('.response-container').appendChild(div);
}
</script>
</body>
</html>
Server:
var express = require("express");
var app = express();
const cors = require("cors");
app.use(cors());
let requestIdx = 1;
app.get("/hello", function (req, res) {
// set cache control headers to expire in 10 seconds
res.setHeader("Cache-Control", "max-age=10");
res.send({
message: "Hello World" + requestIdx++,
});
});
app.listen(3000, function () {
console.log("Server started on port 3000");
});

So, as per your question I guess whatever you've passed from server it would work. In case of cache control there's nothing needs to be done from client. It should always come as part of response header not request header.

Related

How to check in react axios response if response is NotFound()

I am making an api call from React app with axios.
The user selects 2 values from 2 dropdowns, and the api call is made using these 2 values. Normally the response will be an object, but occassionally if the user selects 2 values which dont have a match, then it wont return anything.
I want to ensure a message is displayed if nothing exists for those 2 items.
Currently in my axios response if nothing is return I get a long bunch of what looks like the index html page.
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Web site created using create-react-app"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>React App</title><script defer="defer" src="/static/js/main.adebe8fe.js"></script><link href="/static/css/main.aa245bf1.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
I am getting the data from a c# controller,
[HttpGet("search/{antifungal}/{interacting}")]
public async Task<ActionResult<DrugInteractionDTO>> getAntifungalInteraction(string antifungal, string interacting)
{
var interactions = await _context.DrugInteractions
.Include(di => di.AntifungalAgent)
.Include(di => di.InteractingDrug)
.Where(di => di.AntifungalAgent.Name.ToLower() == antifungal.ToLower())
.Where(di => di.InteractingDrug.GenericName.ToLower() == interacting.ToLower())
.Select(x => new DrugInteractionDTO
{
Severity = x.Severity,
SeverityAsString = x.Severity.ToString(),
ProDetailedInformation = x.ProDetailedInformation,
BasicDetailedInformation = x.BasicDetailedInformation,
Antifungal = x.AntifungalAgent.Name,
InteractingDrug = x.InteractingDrug.GenericName,
ID = x.ID
}).FirstOrDefaultAsync();
if (interactions == null) return NotFound();
return interactions;
}
Using swagger if I enter 2 items in the query that dont exist I get
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.4",
"title": "Not Found",
"status": 404,
"traceId": "00-29b4bb56b99fe26416be4e3c09add6b7-dc13efbf731e6a72-00"
}
So I would have thought calling console.log(response.data) in my axios call would log 404, but it just gives undefined`
This is currently what I have in React,
const getInteractionDetails = () => {
agent.drugInteractions.getIndividual(antifungalDrug, interactingDrug)
.then((response) => {
console.log(response.status)
if(response.status === 404){
setError('No interaction exists')
} else {
setInteractionDetails(response)
}
})
.catch(error => console.log(error))
}
How come status isnt being shown in my axios response?

How to return html file on specific path in deno?

I have a very basic deno app with oak module to build the http server. I want to send a http file, the index.html, only when the path is / (not /anyotherpath).
From oak's github I have this code
app.use(async (ctx, next) => {
try{
await ctx.send({
root: `${Deno.cwd()}/public`,
index:"index.html",
});
}catch{
await next();
}
});
But how do I send the html only for that given path? I also tried with Router
from oak but I couldn't figure out how to serve the html file.
If you only want to respond with the index.html file, and only at the root path /, you can do it the following way:
I've included comments for almost every line of the server example. Feel free to ask any questions in a comment if something is unclear. Be sure to reference the Oak documentation.
./public/index.html:
<!doctype html>
<html lang="en">
<head>
<title>Hello world</title>
</head>
<body>
<h1>Hello world</h1>
</body>
</html>
./main.ts:
import * as path from "https://deno.land/std#0.146.0/path/mod.ts";
import { Application, Router } from "https://deno.land/x/oak#v10.6.0/mod.ts";
// The directory of this module
const moduleDir = path.dirname(path.fromFileUrl(import.meta.url));
// The public directory (with "index.html" in it)
const publicDir = path.join(moduleDir, "public");
// A helper function to get the file contents
// of a specific file path in the public directory
function getPublicFile(...filePath: string[]): Promise<Uint8Array> {
return Deno.readFile(path.join(publicDir, ...filePath));
}
// Create a router
const router = new Router();
// Only handle GET requests to the "/" path
router.get("/", async (ctx, next) => {
// Set the contents of the "index.html" file to the response body
ctx.response.body = await getPublicFile("index.html");
// Set the appropriate resopnse type for HTML
ctx.response.type = "text/html";
// This isn't technically needed here, but it's good practice
// because other middleware might need to run in more complicated routes
await next();
});
// Create the app
const app = new Application();
// Use the router from above
app.use(router.routes());
app.use(router.allowedMethods());
// This is not needed, but is potentially nice for yourself in the console
function printStartupMessage({ hostname, port, secure }: {
hostname: string;
port: number;
secure?: boolean;
}): void {
const address = new URL(
`http${secure ? "s" : ""}://${
hostname === "0.0.0.0" ? "localhost" : hostname
}:${port}/`,
).href;
console.log(`Listening at ${address}`);
console.log("Use ctrl+c to stop");
}
// Run the function above when the server starts listening
app.addEventListener("listen", printStartupMessage);
// Start the server
await app.listen({ port: 8000 });
% deno run --allow-net --allow-read main.ts
Listening at http://localhost:8000/
Use ctrl+c to stop
Requests to http://localhost:8000/ will respond with the index.html file above, and all other routes will respond with a 404 Not Found response.

Sporadic timeouts from directline endpoint

We have deployed a simple Echobot using the Azure template when creating a Web App Bot.
It is currently live at this url: http://18.194.88.194/echobot/
We often experience the following timeout error (about 40% of the time)
WebSocket connection to
'wss://directline.botframework.com/v3/directline/conversations/EH9EbbBIasz8o90sZSeAwT-9/stream?watermark=-&t=ew0KICAiYWxnIj...(snip)
failed: Error in connection establishment:
net::ERR_CONNECTION_TIMED_OUT
Here is our client code:
botclient.js
(async function() {
let {token, conversationId} = sessionStorage;
const delay = 1800000;
//const delay = 20000;
const currentTime = new Date();
const currentTimeUnix = currentTime.getTime();
if (
sessionStorage['startTime'] &&
currentTimeUnix - sessionStorage['startTime'] > delay
) {
sessionStorage.removeItem('token');
token = sessionStorage['token'];
}
const payload = JSON.stringify({botname: 'echobot'});
if (!token) {
const res = await fetch(
'https://ox38xh0fx5.execute-api.eu-central-1.amazonaws.com/dev/directline/token',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: payload,
},
);
const {token: directLineToken} = await res.json();
sessionStorage['token'] = directLineToken;
token = directLineToken;
console.log('token', token);
const startTime = new Date();
const startTimeUnix = startTime.getTime();
sessionStorage['startTime'] = startTimeUnix;
}
const data = {
// from: user,
name: 'requestWelcomeDialog',
type: 'event',
value: {
url: window.location.href,
},
};
var botConnection = new window.WebChat.createDirectLine({token});
window.WebChat.renderWebChat(
{
directLine: botConnection,
userID: 'YOUR_USER_ID',
username: 'Web Chat User',
locale: 'en-US',
},
document.getElementById('webchat'),
);
})().catch(err => console.log(err));
index.html
<!DOCTYPE html>
<html>
<head>
<script src="https://cdn.botframework.com/botframework-webchat/latest/webchat.js"></script>
<style>
html,
body {
height: 100%;
}
body {
margin: 0;
}
#webchat {
height: 100%;
width: 100%;
}
</style>
</head>
<body>
<div id="webchat" role="main"></div>
<script src="botclient.js">
</script>
</body>
</html>
The token is being retrieved from an AWS lambda function with the following code:
import json
import boto3
from urllib.parse import urlencode
from urllib.request import Request, urlopen
BOT_SECRET = 'defaultSecret'
URL = 'https://directline.botframework.com/v3/directline/tokens/generate'
POST_FIELDS = {'foo': 'bar'}
def set_headers(req, secret):
req.add_header('Content-Type', 'application/json')
req.add_header('Authorization', f'Bearer {secret}')
return req
def lambda_handler(event, context):
print(event)
s3 = boto3.client('s3')
if event.get('botname', None) == 'echobot':
response = s3.get_object(Bucket='directline', Key='echobotSecret')
else:
response = s3.get_object(Bucket='directline', Key=BOT_SECRET)
secret = response['Body'].read().decode('utf-8').rstrip()
request = Request(URL, urlencode(POST_FIELDS).encode())
request = set_headers(request, secret)
jsonresponse = urlopen(request).read()
print(jsonresponse)
return jsonresponse
We suspect that there is an issue with the local network configuration, and packets are being dropped. Are there any pointers for how to handle this?
I looked into our backend logs for the conversation ID you included and it looks like the token needs to be refreshed. See the Authentication docs for refreshing tokens.
It looks like your code attempts to account for token expiration, but:
1800000 is the default expiration. It might be best to shorten your delay a bit to account for request travel time and other factors to ensure your tokens don't expire.
You appear to only get the token once, when the chat window is opened. It may expire mid-conversation
That being said, this may not be a token issue. Can you try disabling websockets with:
[...]
window.WebChat.renderWebChat(
{
directLine: botConnection,
userID: 'YOUR_USER_ID',
username: 'Web Chat User',
locale: 'en-US',
webSocket: false // ADD THIS !!!!
},
document.getElementById('webchat'),
[...]
If this is a local packet loss issue, I'm afraid there's not much support I can provide as it's no longer a botframework problem and is likely very specific to your local network. If you can provide additional Conversation IDs, I might be able to dig into this further. But over the last 2 days, your bot appears pretty normal on our side.

Firefox Desktop Notifications not showing when multiple tabs are open

By Web Notification I mean this (The Notification interface of the Notifications API is used to configure and display desktop notifications to the user).
I have Asp.Net MVC web app and I have a button in my page which supposed to push a notification to clients.
I also used signalr to push message and call notification function.
my layout.cshtml looks like this:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>#ViewBag.Title - My ASP.NET Application</title>
</head>
<body>
<button id="btn" type="button">click</button>
#RenderBody()
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script>
<script src="~/signalr/hubs"></script>
<script>
jQuery(function ($) {
var myHub = $.connection.chatHub;
myHub.client.addNewMessageToPage = function (title, message) {
var options = {
body: message,
tag: 'aaa'
}
// check permissions if already granted
if (Notification.permission === "granted") {
var notification = new Notification(title, options);
} else if (Notification.permission !== 'denied') {
// request permission
Notification.requestPermission(function (permission) {
// If the user accepts, let's create a notification
if (permission === "granted") {
var notification = new Notification(title, options);
}
});
}
console.log('the hub method called sucessfully');
}
$.connection.hub.logging = true;
$.connection.hub.start().done(function () {
$('#btn').on('click', function () {
myHub.server.send('foo', 'bar');
});
});
});
</script>
</body>
</html>
The problem is, the push notifications stops working/showing in firefox when I have multiple pages of my app open. (it works when single tab is open).
this bug only happens in firefox and works well in chrome and IE.
update 1:
I think its not signalr problem since the hub method is invoked.
this line is called on all tabs:
console.log('the hub method called sucessfully');
and signalr logging says that:
SignalR: Invoking myhub.Send jquery.signalR-2.2.1.min.js
SignalR: Triggering client hub event 'addNewMessageToPage' on hub 'MyHub'. jquery.signalR-2.2.1.min.js
foo bar
SignalR: Invoked myhub.Send jquery.signalR-2.2.1.min.js
This is a Firefox bug.
The way worked for me was call the Notification in a different time. This is not a complete fix but is working well.
var randomTime = Math.floor((Math.random() * 20) + 1) * 50;
setTimeout(function () {
newNotification = new Notification(Title, NotificationContent);
}, randomTime);
Your question is similar to this one.
And I suggest to use IWC-SignalR from this answer.
This problem is related to Web Socket. You have to enable your websocket first.
$.connection.hub.logging = true;
then you can user socket start function to detect your connections.
$.connection.hub.start({ transport: 'webSockets' }).done(function () { .. });

Need to get profile information after successful login to facebook

Totally new to this API I am working on a web site that uses Facebook API to allow them to log in. The code is old and now does not work so I am trying to upgrade to use new SDK. I am correctly getting them to login using this:
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function () {
FB.init({
appId: '<%= System.Configuration.ConfigurationManager.AppSettings["ApiID"] %>', // App ID
channelUrl: 'http://<%= Request.ServerVariables["SERVER_NAME"] %>/channel.html', // Channel File
status: true, // check login status
cookie: true, // enable cookies to allow the server to access the session
xfbml: true // parse XFBML
});
// Additional initialization code here
};
// Load the SDK Asynchronously
(function (d) {
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) { return; }
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
} (document));
</script>
and this link:
<strong>Login using Facebook</strong>
This seems to work as then you can open facebook.com and you are logged in correctly. However I cannot seem to find how to check this in C#. I have this so far:
//Facebook Authenticated, created session and API object
_connectSession = new FacebookClient();
//example of getting access code
Dictionary<string, object> parameters = new Dictionary<string, object>();
parameters.Add("client_id", System.Configuration.ConfigurationManager.AppSettings["ApiID"]);
parameters.Add("redirect_uri", Request.Url.AbsoluteUri);
parameters.Add("client_secret", System.Configuration.ConfigurationManager.AppSettings["Secret"]);
parameters.Add("scope", "publish_stream,email");
IDictionary<string, object> result = (IDictionary<string, object>)_connectSession.Get("/oauth/access_token", parameters);
string accessToken = (string)result["access_token"];
However I get this error:
(OAuthException - #1) Missing authorization code
If anyone can point me in the direction of how in C# I can get the profile information as we already have the ID in our database I just need to log them in as one of our users.
You're missing the code parameter needed to fetch the access_token - the exception appears to be correct. Check the server side-flow in the Authentication documentation
You likely just need to include the code parameter you received when the user was redirected back to your app from the auth dialog - the other parameters in your call to fetch the access token look correct
I have this test page below, which is code straight from Facebook developers. It is suppose to prompt you to login and then put your picture and name in the elements. While it logs you in correctly it does not update.
** updated code, this now works *
<%# Page Language="C#" AutoEventWireup="true" CodeFile="testfb.aspx.cs" Inherits="testfb" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<head id="Head1" runat="server">
<title></title>
<script type="text/javascript" src="/js/jquery-1.6.1.min.js" charset="utf-8"> </script>
<script src="/js/jquery-ui-1.8.custom.min.js" type="text/javascript"></script>
</head>
<body>
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function () {
FB.init({
appId: '111081862265698', // App ID
channelUrl: '//<%= Request.ServerVariables["SERVER_NAME"] %>/channel.html', // Channel File
status: true, // check login status
cookie: true, // enable cookies to allow the server to access the session
xfbml: true // parse XFBML
});
FB.login(function (response) {
if (response.authResponse) {
alert('Welcome! Fetching your information.... ');
FB.api('/me', function (response) {
alert('Good to see you, ' + response.name + '.');
var image = document.getElementById('image');
image.src = 'http://graph.facebook.com/' + response.id + '/picture';
var name = document.getElementById('name');
name.innerHTML = response.name
});
} else {
alert('User cancelled login or did not fully authorize.');
}
});
};
// Load the SDK Asynchronously
(function (d) {
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) { return; }
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
} (document));
</script>
<div align="center">
<img id="image"/>
<div id="name"></div>
</div>
<div class="fb-login-button" scope="email">
Login with Facebook
</div>
</body>
</html>

Resources