I have the following Javascript code to make a XMLHttpRequest to a server:
function createCORSRequest(method, url) {
var xhr = new XMLHttpRequest();
xhr.open(method, url, true);
return xhr;
}
function makeCorsRequest(word) {
var url = "https://localhost:8080/Method/Dictionary/" + word;
var xhr = createCORSRequest('GET', url);
xhr.onload = function() {
var responseText = xhr.responseText;
document.querySelector("#bar").innerHTML = responseText;
};
xhr.onerror = function() {
document.querySelector("#bar").innerHTML = 'Connection not allowed';
};
xhr.send();
}
makeCorsRequest("word");
At the server, I've got a REST structure (written using Jersey) similiar to:
#Path("/Dictionary")
public class Main{
public Definition returnDefinition(String word){
Definition definition = new Definition();
try{
...//play with Definition object
return definition;
}
catch(IOException IOE){
...
return definition;
}
}
#Path("{word}")
#GET
#Produces("text/xml ; charset=UTF-8") //"Definition" is already set as a XMLRoot element
public Definition main (#PathParam("word") String word){
return returnDefinition(word);
}
}
I try to make this request in two environments:
First environment: The JS code is inside a normal web page. In this case, I receive the following error after trying to make the request:
XMLHttpRequest cannot load http://localhost:8080/Method/Dictionary/word. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
Second environment: The JS code is inside a content script (that is itself inside a chrome extension). In this case, after about 30s of trying to make the request, I receive this:
Failed to load resource: net::ERR_TIMED_OUT
How to proceed?
EDIT: I've added a command to print something at the console in the beginning of the server method. And it is not printed. So, the requests are not reaching the server.
Origin 'null' happens if you are running the page as a file in the browser, using the file:// protocol, rather than set it up in a local webserver and access it using http://.
Related
I have an application that uses NextJS as a wrapper, and I make use of NextJS's dynamic routing feature. I had a problem when deploying it to CloudFront due to dns.com/path/page not being rendered, instead CloudFront expected it to be dns.com/path/page.html. I worked it around by applying this lambda-edge-nice-url solution. It works properly now. However, there's still one issue left: NextJS's dynamic routes. dsn.com/path/subpath/123 should work, since 123 is a dynamic parameter. However, that does no work. In only returns the page when I access dns.com/path/subpath/[id], which of course is not correct, since [id] is not a parameter I want to load.
The strangest thing is: if I try to access the URL as I stated above directly, it fails. However, inside the application I have buttons and links that redirect the user, and that works properly.
Navigating from inside the application (button with router.push inside its callback):
Trying to access the url directly:
Can anyone help me to properly route the requests?
I use a CloudFront Lambda#Edge origin request function to handle re-writing both my dynamic routes as well as static routes to the appropriate HTML file so that CloudFront can serve the intended file for any paths.
My lambda function looks like
export const handler: CloudFrontRequestHandler = async (event) => {
const eventRecord = event.Records[0];
const request = eventRecord.cf.request;
const uri = request.uri;
// handle /posts/[id] dynamic route
if (uri === '/posts' || uri.startsWith('/posts/')) {
request.uri = "/posts/[id].html";
return request;
}
// if URI includes ".", indicates file extension, return early and don't modify URI
if (uri.includes('.')) {
return request;
}
// if URI ends with "/" slash, then we need to remove the slash first before appending .html
if (uri.endsWith('/')) {
request.uri = request.uri.substring(0, request.uri.length - 1);
}
request.uri += '.html';
return request;
};
After trying a lot of different code, I finally came up with a Lambda edge expression that fixed two issues in one:
The need to insert .html in the end of the URL
NextJS dynamic routes that were't working on refresh or when accessed directly to URL.
The code below basically takes care of dynamic routes first. It uses a regex expression to understand the current URL and redirect the request to the proper [id].html file. After that, if the none of the regex are match, and the URL does not contain .html extension, it adds the extension and retrieves the correct file.
const config = {
suffix: '.html',
appendToDirs: 'index.html',
removeTrailingSlash: false,
};
const regexSuffixless = /\/[^/.]+$/; // e.g. "/some/page" but not "/", "/some/" or "/some.jpg"
const regexTrailingSlash = /.+\/$/; // e.g. "/some/" or "/some/page/" but not root "/"
const dynamicRouteRegex = /\/subpath\/\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b/; // e.g /urs/some-uuid; // e.g. '/subpath/uuid'
exports.handler = function handler(event, context, callback) {
const { request } = event.Records[0].cf;
const { uri } = request;
const { suffix, appendToDirs, removeTrailingSlash } = config;
//Checks for dynamic route and retrieves the proper [id].html file
if (uri.match(dynamicRouteRegex)) {
request.uri = "/subpath/[id].html";
callback(null, request);
return;
}
// Append ".html" to origin request
if (suffix && uri.match(regexSuffixless)) {
request.uri = uri + suffix;
callback(null, request);
return;
}
// Append "index.html" to origin request
if (appendToDirs && uri.match(regexTrailingSlash)) {
request.uri = uri + appendToDirs;
callback(null, request);
return;
}
// Redirect (301) non-root requests ending in "/" to URI without trailing slash
if (removeTrailingSlash && uri.match(/.+\/$/)) {
const response = {
// body: '',
// bodyEncoding: 'text',
headers: {
'location': [{
key: 'Location',
value: uri.slice(0, -1)
}]
},
status: '301',
statusDescription: 'Moved Permanently'
};
callback(null, response);
return;
}
// If nothing matches, return request unchanged
callback(null, request);
};
Many thanks to #LongZheng for his answer. For some reason his code did not work for me, but it might for some, so check his answer out. Also, big shoutout to Manc, the creator of this lambda-edge-nice-urls repo. My code is basically a mix of them both.
I am using jersey filter.
In My code logic in AuthenticationFilter.java, if the authorization header is empty, then return the access denied error message.
First time I am hitting the application through rest client tool using the URL without attaching the header
http://localhost:8080/JerseyDemos2/rest/pocservice
Get the status 401 with error message "you cannot access this resource". This is right.
When i tried to hit second time thorugh rest client tool, and server return the exception message.
I deployed my application in tomcat 7.x both windows and linux
Why it give the error when we hit the second time.
How to resolve this
#Provider
public class AuthenticationFilter implements javax.ws.rs.container.ContainerRequestFilter {
#Context
private ResourceInfo resourceInfo;
private static final String AUTHORIZATION_PROPERTY = "Authorization";
private static final Response ACCESS_DENIED = Response.status(Response.Status.UNAUTHORIZED).entity("You cannot access this resource").build();
#Override
public void filter(ContainerRequestContext requestContext) {
// Get request headers
final MultivaluedMap<String, String> headers = requestContext.getHeaders();
// Fetch authorization header
final List<String> authorization = headers.get(AUTHORIZATION_PROPERTY);
// If no authorization information present; block access
if (authorization == null || authorization.isEmpty()) {
requestContext.abortWith(ACCESS_DENIED);
return;
}
}
} }
Error message:
Dec 19, 2016 6:26:18 PM org.glassfish.jersey.server.ServerRuntime$Responder writeResponse
SEVERE: An I/O error has occurred while writing a response message entity to the container output stream.
java.lang.IllegalStateException: The output stream has already been closed.
at org.glassfish.jersey.message.internal.CommittingOutputStream.setStreamProvider(CommittingOutputStream.java:147)
at org.glassfish.jersey.message.internal.OutboundMessageContext.setStreamProvider(OutboundMessageContext.java:803)
......
Please help me
Thanks in advance.
I Removed static variable
private static final Response ACCESS_DENIED = Response.status(Response.Status.UNAUTHORIZED).entity("You cannot access this resource").build();
and i declared local variable. now its working fine.
#Provider
public class AuthenticationFilter implements javax.ws.rs.container.ContainerRequestFilter {
#Context
private ResourceInfo resourceInfo;
private static final String AUTHORIZATION_PROPERTY = "Authorization";
#Override
public void filter(ContainerRequestContext requestContext) {
Response ACCESS_DENIED = Response.status(Response.Status.UNAUTHORIZED).entity("You cannot access this resource").build();
// Get request headers
final MultivaluedMap<String, String> headers = requestContext.getHeaders();
// Fetch authorization header
final List<String> authorization = headers.get(AUTHORIZATION_PROPERTY);
// If no authorization information present; block access
if (authorization == null || authorization.isEmpty()) {
requestContext.abortWith(ACCESS_DENIED);
return;
}
}
} }
You're trying to write in a response that was written before. The full log shows where is it happening. Upload the log and the code where the httpresponse is used/modified.
For our AWS API Endpoints we use AWS_IAM authorization and want to make a call from Swagger UI.
To make a successful call there must be 2 headers 'Authorization' and 'x-amz-date'. To form 'Authorization' we use following steps from aws doc.
We must to change 'x-amz-date' with every call to go through authorization.
The question is: How to write script in Swagger to sign request, which run every time before request send to aws?
(We know how to specify both headers one time before loading Swagger page, but this process should be re-run before every call).
Thanks in advance.
There is built-in support in swagger-js to add requestInterceptors to do just this. The swagger-ui project uses swagger-js under the hood.
Simply create a request interceptor like such:
requestInterceptor: {
apply: function (request) {
// modify the request object here
return request;
}
}
and apply it to your swagger instance on creation:
window.swaggerUi = new SwaggerUi({
url: url,
dom_id: "swagger-ui-container",
requestInterceptor: requestInterceptor,
Here you can set headers in the request object (note, this is not the standard javascript http request object, inspect it for details). But you do have access to all headers here, so you can calculate and inject them as needed.
You can pretty easily monkeypatch signing from the AWS SDK into SwaggerJS(and thus SwaggerUI). See here
I have a slightly modified SwaggerUI here. Given some AWS credentials and an API ID, it will pull down the Swagger definition, display it in SwaggerUI, and then you can call the API using sigv4.
The Authorizer implementation looks like this:
var AWSSigv4RequestSigner = function(credentialProvider, aws) {
this.name = "sigv4";
this.aws = aws;
this.credentialProvider = credentialProvider;
};
AWSSigv4RequestSigner.prototype.apply = function(options, authorizations) {
var serviceName = "execute-api";
//If we are loading the definition itself, then we need to sign for apigateway.
if (options && options.url.indexOf("apigateway") >= 0) {
serviceName = "apigateway";
}
if(serviceName == "apigateway" || (options.operation && options.operation.authorizations && options.operation.authorizations[0].sigv4))
{
/**
* All of the below is an adapter to get this thing into the right form for the AWS JS SDK Signer
*/
var parts = options.url.split('?');
var host = parts[0].substr(8, parts[0].indexOf("/", 8) - 8);
var path = parts[0].substr(parts[0].indexOf("/", 8));
var querystring = parts[1];
var now = new Date();
if (!options.headers)
{
options.headers = [];
}
options.headers.host = host;
if(serviceName == "apigateway")
{
//For the swagger endpoint, apigateway is strict about content-type
options.headers.accept = "application/json";
}
options.pathname = function () {
return path;
};
options.methodIndex = options.method;
options.search = function () {
return querystring ? querystring : "";
};
options.region = this.aws.config.region || 'us-east-1';
//AWS uses CAPS for method names, but swagger does not.
options.method = options.methodIndex.toUpperCase();
var signer = new this.aws.Signers.V4(options, serviceName);
//Actually add the Authorization header here
signer.addAuthorization(this.credentialProvider, now);
//SwaggerJS/yourbrowser complains if these are still around
delete options.search;
delete options.pathname;
delete options.headers.host;
return true;
}
return false;
};
Please ignore the spelling mistake, I cannot copy code so I have typed the whole thing and changed name of controller and method.
WEB API 2
Controller:
// Controller name is Test
public HttpResponseMessage Method1(int param1) // Post method
{
// return string
}
If I create an object of controller in test case then it is working fine. But if I want to test in localhost using following code:
Unit Test:
public void Method1Test()
{
HttpResponseMessage response;
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}");
HttpServer server = new HttpServer(config);
using(var client = new HttpClient(server))
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:5022/api/test?param1=1");
request.Content = new ObjectContent<int>(param1, new JsonMediaTypeFormatter());
response = client.SendAsync(request, CancellationToken.None).Result;
};
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
Now, my test case is failing. I used the same code in different project and it worked. May be it is the way I am trying to call Post method. Is this the right way to call post method with Int parameter in URL?
In help page, under API column it shows:
POST api/test/param1={param1}
Also I have put some stop point in actual service I am cursor is not stopping at that point. Why?
If I want to call the same service from browser, what URL should I pass? Is it -
http://localhost:5022/api/test?param1=1
Or something else?
I figured it out. Following is the correct unit test method but this has some extra information which I have not provided earlier i.e., passing object as an input for the service.
private void Method1Test(ObjectClass obj)
{
HttpResponseMessage response = null;
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}");
HttpServer server = new HttpServer(config);
using (var client = new HttpClient(server))
{
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost:5022/api/test/1");
request.Content = new ObjectContent<ObjectClass>(obj, new JsonMediaTypeFormatter());
response = client.SendAsync(request, CancellationToken.None).Result;
};
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
So the correct URL that I was looking for was
http://localhost:5022/api/test/1
Sorry, It took long to post this answer. This method is working like a charm for more then 2 years.
I'm a complete Flex noob, so I apologize in advance if I'm missing something obvious.
I wrote a fairly simple file uploader in Flex, which calls my Django back-end via URLRequest (the FileReference object handles the upload). My upload works as intended and I have Django return a HTTPResponse object. As such, I'd like to read the contents of the HTTPResponse object.
Any thoughts?
something along the lines of
<mx:HTTPService id="myHTTPRequest"
url="{whatever your url request is}"
result="resultHandler(event)"
fault="faultHandler(event)"
showBusyCursor="true"
resultFormat="object">
then inside the resultHandler something like this
private function resultHandler (event : ResultEvent) : void {
var obj : Object = event.result;
//do something with returned object
}
Debug at the point of the resultHandler to see exaclty whats being returned, make sure its what you think should be getting returned.
By the time it gets to the client it's just a normal HTTP response so treat it like any other response
I am also new to flex and I ran in the same problem when doing an upload to a Java Rest backend, I solved it using the DateEvent on the FileReference. To get the response data use something like this.:
var fileRef:FileReference = new FileReference();
fileRef.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, responseHandler);
var request:URLRequest = new URLRequest("yourUrl");
fileRef.upload(request, "fileData");
private function responseHandler(event:DataEvent):void {
var response:XML = new XML(event.data);
//Note the DataEvent: this is the event that holds the response.
//I sent back data as xml
}
Your response should always be a successful HTTP status code (200), if your backend sends status 500 codes it will not trigger the DateEvent. Server errors can still be caught with a HTTPStatusEvent, but then you don't have access to the response.
you can access the response like so in your onComplete event handler:
private function saveCompleteHandler(event:Event):void {
var loader:URLLoader = event.currentTarget as URLLoader;
trace("saveCompleteHandler - event returned:" + loader.data as String);
}
we do this this to get json fron a java web service.
you just need to use a URLLoader to load the URLRequest in the first place:
var loader:URLLoader = new URLLoader();
loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, statusHandler, 10000);
loader.addEventListener(IOErrorEvent.IO_ERROR, saveErrorHandler, 10000);
loader.addEventListener(Event.COMPLETE, saveCompleteHandler, 10000);
var request:URLRequest = new URLRequest("http:/whereverer");
request.method = URLRequestMethod.GET;
loader.load(request);