I am trying out the dependency injection for Azure Function.
I have the following super simple code block
[FunctionName("CosmosWriteTest")]
public async Task<IActionResult> CosmosWriteTest([HttpTrigger(AuthorizationLevel.Anonymous, "post", Route = null)] HttpRequest req, ILogger log)
{
log.LogInformation("C# HTTP trigger function processed a request.");
return new OkObjectResult("");
}
As you can see, the type of this function is Post. I then copy the URL of this function from the console and paste it into the web browser. I received the "This localhost page can’t be found" error.
I tried to modify the type from post to get, or to "post, get", it works.
Any idea what's going on here?
Here is the http-triggered Function's description from official document:
The HTTP trigger lets you invoke a function with an HTTP request. You
can use an HTTP trigger to build serverless APIs and respond to
webhooks.
You could run a function from an HTTP request (http trigger) and return an HTTP response from a function (http output) using Postman and curl, or access the url with the query string like this:
If you are using portal, you can also test it directly:
Related
I'm trying to trasform http GET method call from legacy api server built with MVC1 pattern to new restful api server without any change of front-end source code using netflix zuul and eureka.
I added zuul pre filter transforming legacy url to restful convention url working after PreDecorationFilter and it works fine.
But now I'm facing problem converting the GET method to proper method like POST, PUT, DELETE by distinguising url so that the requests are properly mapped in spring controller via #GetMapping/#PostMapping/#PutMapping/#DeleteMapping.
I looked into SimpleRoutingFilter that handles HttpClient but
Because of environmental constraint, I have to use eureka service id to route to the new api server and that means I should use RibbonRoutingFilter which is quite complicated to find out a right place to this operation in.
So, is this possible to change http method or make new http request before RibbonRoutingFilter?
If possible can you please suggest where is the right place to do that or some reference?
Many thanks!
======================================================================
Milenko Jevremovic,
Would you please tell me more detail about using Feign?
I defiend #FeignClient like below
#PostMapping(value = "{url"}, consumes = "application/json")
ResponseEntity<?> postMethod(#PathVariable("url") String url);
and to get query parameters to request body for POST In zuul pre filter,
after transform logic from GET request url to POST new restful url ...
byte[] bytes = objectMapper.writeValueAsBytes(ctx.get("requestQueryParams"));
ctx.setRequests(new HttpServletRequestWrapper(request) {
#Override ..getMethod
#Override ..getContentLength
#Override ..getConentLengthLong
#Override
public ServletInputStream getInputStream() {
return new ServletInputStreamWrapper(bytes);
}
}
ResponseEntity<?> response feignClient.post(transformedNewApiUri);
and set RequestContext code that you suggested ....
and controller of new api server is like,
#PostMapping
ResponseEntity<model> post(#RequestBody req..)
It comes to controller fine but when I see the http request in post method of controller,
There is no request body for parameters.
(HttpServleterRequest getInputStream shows empty)
The request data set in zuul pre filter by HttpServletRequestWrapper is
not used in Feign maybe...?
Would you please get me more idea setting request body when changing GET query
to POST constructor for using Feign?
It is not possible to change method of HttpServletRequest, but it's possible to replace request in RequestContext. HttpServletRequestWrapper appears to be very helpful:
static class PostHttpServletRequest extends HttpServletRequestWrapper {
public PostHttpServletRequest(HttpServletRequest request) {
super(request);
}
#Override
public String getMethod() {
return "POST";
}
}
So method run can be rewritten as following:
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletRequest requestWrapper = new PostHttpServletRequest(request);
ctx.setRequest(requestWrapper);
return null;
}
After doing some research did not find any built in solution.
But what comes in my mind you can use Feign client in your Pre filter, get the response, set the response and return it immediately to client from your Pre filter.
You can set Feign client url or your service id, like it is explained in the docs, it uses ribbon as well .
Change response in your run method like:
...
RequestContext ctx = RequestContext.getCurrentContext();
ctx.setResponseStatusCode(your_code);
ctx.setResponseBody(new_body);
ctx.setSendZuulResponse(false);
return null
I'm creating ASP.NET MVC controller, which would proxy requests to remote service and after response is got - resend response to the client. It works fine, but I get System.Net.WebException when remote server returns (400) Bad Request.
Is there any way how to proxy any kind of response to the client, without raising such exeptions?
var request = (HttpWebRequest)WebRequest.Create(uri);
Request.CopyTo(request);
var response = (HttpWebResponse)request.GetResponse();
return new HttpWebResponseResult(response);
All web client API provided with .NET framework are designed to send an exception everytime it sees a 4XX or 5XX error. If you want to override this behaviour, you have to wrap your webRequest or webclient call inside try/catch.
As proxying means lot of waiting, to avoid consuming too much ressource and fasten your answer, prefer defining your controller method as async and await the answer :
var request = (HttpWebRequest)WebRequest.Create(uri);
var response = await Task<HttpWebResponse>.Factory.FromAsync(request.BeginGetResponse, request.EndGetResponse);
return new HttpWebResponseResult(response);
I've been going crazy here trying to get jquery.ajax to work with ie9. So I have a ASP Web API 2 Rest API that implements CORS. CORS requests from all browsers work. IE9 didnt work since it uses the XDomainRequest. I managed to get it too work by making a custom implementation of ajaxTransport for IE9.
Right now GET requests seem to work fine. But when I do a post request from IE9 I get a HTTP error 415 - unsuportted media type.
I've set the content-type to:"application/json" and I've also tried "application/x-www-form-urlencoded", but from what I understood XDomainRequest doesnt support everything with custom headers? Does anybody know if something specific needs to be setup on the WebAPI or do I need to tweak the request?
My request looks like this:
$.ajax({
url: hostname + "/api/DDC/Book",
type: "POST",
contentType: "application/json",
data: {
DealID: function () {
return viewModel.get("DealID");
},
LocationID: function () {
return viewModel.get("LocationID");
},
Time: function () {
return viewModel.get("selectedDateTime.Time");
}
}
})
On the server I have this:
[HttpPost("DDC/Book")]
[EnableCors(origins: "*", headers: "*", methods: "POST, GET, OPTIONS, PUT, DELETE")]
public dynamic Post(BookModel model)
{
.........
When I analyze the failed request in the IE debugger this are the request headers that get sent out:
Key Value
Request POST //api/DDC/Book HTTP/1.1
Accept */*
Origin http://myurl.com
Accept-Language hr-HR
Accept-Encoding gzip, deflate
User-Agent Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)
Host www.somehost.com
Content-Length 55
DNT 1
Connection Keep-Alive
Cache-Control no-cache
I'm really losing all hope here and IE is making my go crazy (damn you Microsoft :D ), so any help or advice is much appriciated.
EDIT: From more reasearch I found out that WebAPI requires a content-type to work and XDomainRequest doesnt send out one. So the only solution I see is too tweak my webapi to have a default content-type when nothing is set. Don't know how to this yet though
EDIT2: Hacked my way through temporarily by transforming all my POSTs, to GETs, dont know how smart is this, but I see no bigger problem with it now, so it will do until I fix the problem
Managed to solve it myself. As pointed by Ray Nicholus when there is no Content-Type ASP Web API defaults to an "application/octet-stream" Content-Type. I need a default of "application/x-www-form-urlencoded".
I managed to achive this by writing my own simple message handler that checks an incoming requests "Content-Type" and if nothing is present it adds an "application/x-www-form-urlencoded" one.
This is the code:
public class DefaultContentTypeMessageHandler : DelegatingHandler
{
protected async override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Content.Headers.ContentType == null)
request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
var response = await base.SendAsync(request, cancellationToken);
return response;
}
}
UPDATE:
As written by Robert Christ in the comment below I am extending the answer a bit for those who have not worked with message handlers before:
For those who don't understand at first glance, DelegatingHandlers
allow you to modify requests / response objects before they really hit
the WebAPI framework internals. Nothing else in the framework really
lets you modify the incoming request before model binding, without
actually writing custom model binders (eugh). so instead, here, you
can sniff out a null content type (which is guaranteed by shortcomings
in the XDomainRequest spec), update it to xml or json, and you will be
able to parse the incoming request correctly.
After you have written a message handler you need to register it with WebAPI. You do that in the WebApiConfig class:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new DefaultContentTypeMessageHandler());
// Rest of your code
}
}
Just to confirm what you have already edited into your question over several updates: yes, XDomainRequest does not include a Content-Type header in the request. As you may know by now, you can't set any headers via this transport.
The lack of a Content-Type is particularly problematic for most server-side frameworks, as this means they will be unable to parse the content of the response automatically. In the absence of a Content-Type header, RFC 2616 says the body is assumed to be application/octet-stream, which is likely not what you want in this case. So, you'll need to "manually" parse the request body server-side by hard-coding the expected Content-Type for the associated request in this case.
I would strongly recommend you not simply convert all of your POSTs to GETs. GET requests should be "safe", per RFC 2616. By simply renaming all of your POSTs to GETs, you are no longer following the defined and accepted semantics of GET requests. In other words, don't do this.
Dennis' answer above uses async which is only available in .NET 4.5. For .NET 4 and possibly lower, use the following delegating handler instead:
public class DefaultContentTypeMessageHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.Method == HttpMethod.Post && request.Content.Headers.ContentType == null)
{
request.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/x-www-form-urlencoded");
}
return base.SendAsync(request, cancellationToken);
}
}
Also, don't forget your USING statements, you will need:
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
I'm developing a dart application which will consume a REST service I'm building. I started writing out the dart code to perform an ajax request to my login endpoint. However, even when my dart ajax request should fail, it claims to succeed.
I don't have any services up and running (and even if I did it would be using the wrong domain / port right now), but this code gives a 200 OK HttpResponse every time:
class PlayerController {
const PlayerController();
static const String LOGIN_URL = "login";
void login(String username, String password) {
Map<String, String> headers = {"Content-Type": "application/x-www-form-urlencoded"};
String body = "j_username=$username&j_password=$password&submit=Login";
HttpRequest.request(LOGIN_URL, method: "POST", requestHeaders: headers, sendData: body)
.then((request) => processLogin(request, username))
.catchError((e) => processLoginError(e));
}
void processLogin(var whatIsThis, String username) {
query("#loginButton").text = "Logout";
//TODO get the player then set them
}
void processLoginError(var e) {
print("total failure to login because of $e");
}
}
It always hits the processLogin method, and never hits the processLoginError method. Does anyone have any idea why this would be? Should I be performing this ajax request in a different way? (If you couldn't guess, it will be signing into spring security).
I read somewhere that file system requests always succeed. Is Dart somehow making this a file system request rather than a web request?
This is because the request actually completes successfully.
Your request to "login" will actually call http://127.0.0.1:6521/[Path_to_your_Dart_file]/login
The server started by Dart when running in Dartium (127.0.0.1:6521) seems to answer to every POST request with HTTP 200 and an empty response body.
If you change the method from POST to GET, it will fail as expected.
As for why the server does this - I don't really know. This would have to be answered by the Dart team.
Background
Generate a report in various formats (e.g., PDF, delimited, HTML) using an ADF Task Flow.
Problem
HTTP headers are being sent twice: once by the framework and once by a bean.
Source Code
The source code includes:
Button Action
Managed Bean
Task Flow
Button Action
The button action:
<af:commandButton text="Report" id="submitReport" action="Execute" />
Managed Bean
The Managed Bean is fairly complex. The code to responseComplete is getting called, however it does not seem to be called sufficiently early to prevent the application framework from writing the HTTP headers.
HTTP Response Header Override
/**
* Sets the HTTP headers required to indicate to the browser that the
* report is to be downloaded (rather than displayed in the current
* window).
*/
protected void setDownloadHeaders() {
HttpServletResponse response = getServletResponse();
response.setHeader( "Content-Description", getContentDescription() );
response.setHeader( "Content-Disposition", "attachment, filename="
+ getFilename() );
response.setHeader( "Content-Type", getContentType() );
response.setHeader( "Content-Transfer-Encoding",
getContentTransferEncoding() );
}
Issue Response Complete
getFacesContext().responseComplete();
Bean Run and Configure
public void run() {
try {
Report report = getReport();
configure(report.getParameters());
report.run();
} catch (Exception e) {
e.printStackTrace();
}
}
private void configure(Parameters p) {
p.put(ReportImpl.SYSTEM_REPORT_PROTOCOL, "http");
p.put(ReportImpl.SYSTEM_REPORT_HOST, "localhost");
p.put(ReportImpl.SYSTEM_REPORT_PORT, "7002");
p.put(ReportImpl.SYSTEM_REPORT_PATH, "/reports/rwservlet");
p.put(Parameters.PARAM_REPORT_FORMAT, "pdf");
p.put("report_cmdkey", getReportName());
p.put("report_ORACLE_1", getReportDestinationType());
p.put("report_ORACLE_2", getReportDestinationFormat());
}
Task Flow
The Task Flow calls Execute, which refers to the bean's run() method:
entry -> main -> Execute -> ReportBeanRun
Where:
<method-call id="ReportBeanRun">
<description>Executes a report</description>
<display-name>Execute Report</display-name>
<method>#{reportBean.run}</method>
<outcome>
<fixed-outcome>success</fixed-outcome>
</outcome>
</method-call>
The bean is assigned to the request scope, with a few managed properties:
<control-flow-rule id="__3">
<from-activity-id>main</from-activity-id>
<control-flow-case id="ExecuteReport">
<from-outcome>Execute</from-outcome>
<to-activity-id>ReportBeanRun</to-activity-id>
</control-flow-case>
</control-flow-rule>
<managed-bean id="ReportBean">
<description>Executes a report</description>
<display-name>ReportBean</display-name>
<managed-bean-scope>request</managed-bean-scope>
...
</managed-bean>
The <fixed-outcome>success</fixed-outcome> strikes me as incorrect -- I don't want the method call to return to another task.
Restrictions
The report server receives requests from the web server exclusively. The report server URL cannot be used by browsers to download directly, for security reasons.
Error Messages
The error message that is generated:
Duplicate headers received from server
Error 349 (net::ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION): Multiple distinct Content-Disposition headers received. This is disallowed to protect against HTTP response splitting attacks.
Nevertheless, the report is being generated. Preventing the framework from writing the HTTP headers would resolve this issue.
Question
How can you set the HTTP headers in ADF while using a Task Flow to generate a PDF by calling a managed bean?
Ideas
Some additional ideas:
Override the Page Lifecycle Phase Listener (ADFPhaseListener + PageLifecycle)
Develop a custom Servlet on the web server
Related Links
http://www.oracle.com/technetwork/middleware/bi-publisher/adf-bip-ucm-integration-179699.pdf
http://www.slideshare.net/lucbors/reports-no-notes#btnNext
http://www.techartifact.com/blogs/2012/03/calling-oracle-report-from-adf-applications.html?goback=%2Egde_4212375_member_102062735
http://docs.oracle.com/cd/E29049_01/web.1112/e16182/adf_lifecycle.htm#CIABEJFB
Thank you!
The problem was an incorrect implementation of RFC 2183:
response.setHeader( "Content-Disposition", "attachment; filename="
+ getFilename() );
The ; cannot be a ,.